Add magimail (crashmail2 fork) to repo

This commit is contained in:
Andrew Pamment 2017-03-18 23:04:38 +10:00
parent 8fad85affc
commit 807574ccf4
98 changed files with 23583 additions and 7 deletions

View File

@ -5,7 +5,7 @@ JAMLIB = deps/jamlib/jamlib.a
ZMODEM = deps/Xmodem/libzmodem.a ZMODEM = deps/Xmodem/libzmodem.a
LUA = deps/lua/liblua.a LUA = deps/lua/liblua.a
all: magicka all: magicka magimail
${LUA}: ${LUA}:
cd deps/lua && $(MAKE) -f Makefile freebsd MAKEFLAGS= cd deps/lua && $(MAKE) -f Makefile freebsd MAKEFLAGS=
@ -23,6 +23,9 @@ OBJ = inih/ini.o bbs.o main.o users.o main_menu.o mail_menu.o doors.o bbs_list.o
magicka: $(OBJ) ${LUA} ${JAMLIB} ${ZMODEM} magicka: $(OBJ) ${LUA} ${JAMLIB} ${ZMODEM}
$(CC) -o magicka -o $@ $^ $(CFLAGS) -L/usr/local/lib -lsqlite3 $(JAMLIB) $(ZMODEM) $(LUA) -lutil -lm -lssl -lcrypto -lssh $(CC) -o magicka -o $@ $^ $(CFLAGS) -L/usr/local/lib -lsqlite3 $(JAMLIB) $(ZMODEM) $(LUA) -lutil -lm -lssl -lcrypto -lssh
magimail: $(JAMLIB)
cd utils/magimail && $(MAKE) freebsd
.PHONY: clean .PHONY: clean
clean: clean:
@ -30,3 +33,4 @@ clean:
cd deps/lua && $(MAKE) clean cd deps/lua && $(MAKE) clean
cd deps/jamlib && $(MAKE) -f Makefile.linux clean cd deps/jamlib && $(MAKE) -f Makefile.linux clean
cd deps/Xmodem && $(MAKE) clean cd deps/Xmodem && $(MAKE) clean
cd utils/magimail && $(MAKE) cleanfreebsd

View File

@ -7,7 +7,7 @@ LUA = deps/lua/liblua.a
B64 = deps/libb64-1.2/src/libb64.a B64 = deps/libb64-1.2/src/libb64.a
MICROHTTPD=-lmicrohttpd MICROHTTPD=-lmicrohttpd
all: magicka all: magicka magimail
${LUA}: ${LUA}:
cd deps/lua && $(MAKE) -f Makefile freebsd MAKEFLAGS= cd deps/lua && $(MAKE) -f Makefile freebsd MAKEFLAGS=
@ -28,6 +28,9 @@ OBJ = inih/ini.o bbs.o main.o users.o main_menu.o mail_menu.o doors.o bbs_list.o
magicka: $(OBJ) ${LUA} ${ZMODEM} ${JAMLIB} ${B64} magicka: $(OBJ) ${LUA} ${ZMODEM} ${JAMLIB} ${B64}
$(CC) -o magicka -o $@ $^ $(CFLAGS) -L/usr/local/lib -lsqlite3 $(JAMLIB) $(ZMODEM) $(LUA) $(B64) -lutil -lm -lssl -lcrypto -lssh $(MICROHTTPD) $(CC) -o magicka -o $@ $^ $(CFLAGS) -L/usr/local/lib -lsqlite3 $(JAMLIB) $(ZMODEM) $(LUA) $(B64) -lutil -lm -lssl -lcrypto -lssh $(MICROHTTPD)
magimail: $(JAMLIB)
cd utils/magimail && $(MAKE) freebsd
.PHONY: clean .PHONY: clean
clean: clean:
@ -36,3 +39,4 @@ clean:
cd deps/jamlib && $(MAKE) -f Makefile.linux clean cd deps/jamlib && $(MAKE) -f Makefile.linux clean
cd deps/Xmodem && $(MAKE) clean cd deps/Xmodem && $(MAKE) clean
cd deps/libb64-1.2 && $(MAKE) clean cd deps/libb64-1.2 && $(MAKE) clean
cd utils/magimail && $(MAKE) cleanfreebsd

View File

@ -6,7 +6,7 @@ ZMODEM = deps/Xmodem/libzmodem.a
LUA = deps/lua/liblua.a LUA = deps/lua/liblua.a
all: magicka all: magicka magimail
${LUA}: ${LUA}:
cd deps/lua && $(MAKE) -f Makefile linux MAKEFLAGS= cd deps/lua && $(MAKE) -f Makefile linux MAKEFLAGS=
@ -24,6 +24,9 @@ OBJ = inih/ini.o bbs.o main.o users.o main_menu.o mail_menu.o doors.o bbs_list.o
magicka: $(OBJ) ${LUA} ${ZMODEM} ${JAMLIB} magicka: $(OBJ) ${LUA} ${ZMODEM} ${JAMLIB}
$(CC) -o magicka -o $@ $^ $(CFLAGS) -L/usr/local/lib -lsqlite3 $(JAMLIB) $(ZMODEM) $(LUA) -lutil -lm -ldl -lssl -lcrypto -lssh $(CC) -o magicka -o $@ $^ $(CFLAGS) -L/usr/local/lib -lsqlite3 $(JAMLIB) $(ZMODEM) $(LUA) -lutil -lm -ldl -lssl -lcrypto -lssh
magimail: $(JAMLIB)
cd utils/magimail && $(MAKE) linux
.PHONY: clean .PHONY: clean
clean: clean:
@ -31,3 +34,4 @@ clean:
cd deps/lua && $(MAKE) clean cd deps/lua && $(MAKE) clean
cd deps/jamlib && $(MAKE) -f Makefile.linux clean cd deps/jamlib && $(MAKE) -f Makefile.linux clean
cd deps/Xmodem && $(MAKE) clean cd deps/Xmodem && $(MAKE) clean
cd utils/magimail && $(MAKE) cleanlinux

View File

@ -7,7 +7,7 @@ LUA = deps/lua/liblua.a
B64 = deps/libb64-1.2/src/libb64.a B64 = deps/libb64-1.2/src/libb64.a
MICROHTTPD=-lmicrohttpd MICROHTTPD=-lmicrohttpd
all: magicka all: magicka magimail
${LUA}: ${LUA}:
cd deps/lua && $(MAKE) -f Makefile linux MAKEFLAGS= cd deps/lua && $(MAKE) -f Makefile linux MAKEFLAGS=
@ -29,6 +29,9 @@ OBJ = inih/ini.o bbs.o main.o users.o main_menu.o mail_menu.o doors.o bbs_list.o
magicka: $(OBJ) ${LUA} ${JAMLIB} ${ZMODEM} ${B64} magicka: $(OBJ) ${LUA} ${JAMLIB} ${ZMODEM} ${B64}
$(CC) -o magicka -o $@ $^ $(CFLAGS) -L/usr/local/lib -lsqlite3 $(JAMLIB) $(ZMODEM) $(LUA) $(B64) -lutil -lm -ldl -lssl -lcrypto -lssh $(MICROHTTPD) $(CC) -o magicka -o $@ $^ $(CFLAGS) -L/usr/local/lib -lsqlite3 $(JAMLIB) $(ZMODEM) $(LUA) $(B64) -lutil -lm -ldl -lssl -lcrypto -lssh $(MICROHTTPD)
magimail: $(JAMLIB)
cd utils/magimail && $(MAKE) linux
.PHONY: clean .PHONY: clean
clean: clean:
@ -37,4 +40,4 @@ clean:
cd deps/jamlib && $(MAKE) -f Makefile.linux clean cd deps/jamlib && $(MAKE) -f Makefile.linux clean
cd deps/Xmodem && $(MAKE) clean cd deps/Xmodem && $(MAKE) clean
cd deps/libb64-1.2 && $(MAKE) clean cd deps/libb64-1.2 && $(MAKE) clean
cd utils/magimail && $(MAKE) cleanlinux

View File

@ -7,7 +7,7 @@ LUA = deps/lua/liblua.a
OBJ = inih/ini.o bbs.o main.o users.o main_menu.o mail_menu.o doors.o bbs_list.o chat_system.o email.o files.o settings.o lua_glue.o strings.o bluewave.o hashmap/hashmap.o OBJ = inih/ini.o bbs.o main.o users.o main_menu.o mail_menu.o doors.o bbs_list.o chat_system.o email.o files.o settings.o lua_glue.o strings.o bluewave.o hashmap/hashmap.o
all: magicka all: magicka magimail
${LUA}: ${LUA}:
cd deps/lua && $(MAKE) -f Makefile macosx MAKEFLAGS= cd deps/lua && $(MAKE) -f Makefile macosx MAKEFLAGS=
@ -24,6 +24,9 @@ ${ZMODEM}:
magicka: $(OBJ) ${LUA} ${ZMODEM} ${JAMLIB} magicka: $(OBJ) ${LUA} ${ZMODEM} ${JAMLIB}
$(CC) -o magicka -o $@ $^ $(CFLAGS) -L/opt/local/lib -lsqlite3 $(JAMLIB) $(ZMODEM) $(LUA) -lutil -lm -ldl -lssl -lcrypto -lssh $(CC) -o magicka -o $@ $^ $(CFLAGS) -L/opt/local/lib -lsqlite3 $(JAMLIB) $(ZMODEM) $(LUA) -lutil -lm -ldl -lssl -lcrypto -lssh
magimail: $(JAMLIB)
cd utils/magimail && $(MAKE) linux
.PHONY: clean .PHONY: clean
clean: clean:
@ -31,3 +34,4 @@ clean:
cd deps/lua && $(MAKE) clean cd deps/lua && $(MAKE) clean
cd deps/jamlib && $(MAKE) -f Makefile.linux clean cd deps/jamlib && $(MAKE) -f Makefile.linux clean
cd deps/Xmodem && $(MAKE) clean cd deps/Xmodem && $(MAKE) clean
cd utils/magimail && $(MAKE) cleanlinux

View File

@ -8,7 +8,7 @@ B64 = deps/libb64-1.2/src/libb64.a
MICROHTTPD=-lmicrohttpd MICROHTTPD=-lmicrohttpd
all: magicka all: magicka magimail
${LUA}: ${LUA}:
cd deps/lua && $(MAKE) -f Makefile macosx MAKEFLAGS= cd deps/lua && $(MAKE) -f Makefile macosx MAKEFLAGS=
@ -29,6 +29,9 @@ OBJ = inih/ini.o bbs.o main.o users.o main_menu.o mail_menu.o doors.o bbs_list.o
magicka: $(OBJ) ${LUA} ${ZMODEM} ${JAMLIB} ${B64} magicka: $(OBJ) ${LUA} ${ZMODEM} ${JAMLIB} ${B64}
$(CC) -o magicka -o $@ $^ $(CFLAGS) -L/opt/local/lib -lsqlite3 $(JAMLIB) $(ZMODEM) $(LUA) $(B64) -lutil -lm -ldl -lssl -lcrypto -lssh $(MICROHTTPD) $(CC) -o magicka -o $@ $^ $(CFLAGS) -L/opt/local/lib -lsqlite3 $(JAMLIB) $(ZMODEM) $(LUA) $(B64) -lutil -lm -ldl -lssl -lcrypto -lssh $(MICROHTTPD)
magimail: $(JAMLIB)
cd utils/magimail && $(MAKE) linux
.PHONY: clean .PHONY: clean
clean: clean:
@ -36,3 +39,4 @@ clean:
cd deps/lua && $(MAKE) clean cd deps/lua && $(MAKE) clean
cd deps/jamlib && $(MAKE) -f Makefile.linux clean cd deps/jamlib && $(MAKE) -f Makefile.linux clean
cd deps/Xmodem && $(MAKE) clean cd deps/Xmodem && $(MAKE) clean
cd utils/magimail && $(MAKE) cleanlinux

25
utils/magimail/Makefile Normal file
View File

@ -0,0 +1,25 @@
# type either "make linux", "make win32", or "make os2" to compile
help:
@echo You can use this Makefile in the following ways:
@echo gmake freebsd ......... Make FreeBSD binaries
@echo make linux ............ Make Linux binaries
@echo gmake cleanfreebsd .... Remove object files under FreeBSD
@echo make cleanlinux ....... Remove object files under Linux
freebsd :
mkdir -p bin
gmake -C src -f Makefile freebsd
linux :
mkdir -p bin
make -C src -f Makefile linux
cleanfreebsd :
rm -rf bin
gmake -C src -f Makefile cleanfreebsd
cleanlinux :
rm -rf bin
make -C src -f Makefile cleanlinux

75
utils/magimail/README Normal file
View File

@ -0,0 +1,75 @@
magimail is derived from...
CrashMail II
The Next Generation!
...a stranger in a strange land...
============
Introduction
============
Welcome to CrashMail II! CrashMail II is basically a more portable version
of CrashMail, a tosser for Amiga computers. Users of the old Amiga
version will probably find some things familiar while some features are
gone such as the ARexx port (for obvious reasons!) and the GUI
configuration editor. The only feature that CrashMail II has and the old
CrashMail hasn't is support for JAM messagebases.
Homepage: http://ftnapps.sourceforge.net/crashmail.html
Code: http://sourceforge.net/p/ftnapps/crashmail/code/
Downloads: http://sourceforge.net/projects/ftnapps/files/crashmail/
=========
Copyright
=========
Copyright (C) 1998-2004, Johan Billing <billing@df.lth.se>
Copyright (C) 1999-2010, Peter Krefting <peter@softwolves.pp.se>
Copyright (C) 2009-2014, Robert James Clay <jame@rocasa.us>
Copyright (C) 2013, Lars Kellogg-Stedman <lars@oddbit.com>
JAMLIB is copyright (c) 1999 Björn Stenberg. JAMLIB is released under the
GNU Lesser General Public License, See src/jamlib/jamlib.doc for more
information.
tests/roundup is copyright (c) 2010 Blake Mizerany - MIT License
Except where explicitly stated otherwise, all other parts of CrashMail are
copyright 1998-2004 Johan Billing. Permission to use, copy and distribute
CrashMail is granted provided that this copyright notice is included. Permission
to modify CrashMail is granted. Distributing modified versions of CrashMail is
allowed provided that the documentation clearly states that it is a modified
version. Parts of CrashMail may be freely used in other projects as long as
the documentation mentions the original copyright holder.
================
Acknowledgements
================
Many thanks to Björn Stenberg for creating the excellent subroutine library
JAMLIB which CrashMail uses for handling JAM messagebases.
Thanks for Peter Karlsson for porting CrashMail II to OS/2 and the man pages.
=============
Documentation
=============
The documentation is very brief and CrashMail probably isn't the ideal
choice for Fidonet beginners. All documentation of the available keywords
in the configuration file can be found in the doc/example.prefs file, and
other information can be found in the doc/ReadMe.txt file..
=========
Platforms
=========
This version of CrashMail can be compiled for Win32, Linux and OS/2; see the
INSTALL file for details. If you are interested in running CrashMail on another
platform, please contact me if you are willing to do the work necessary to adapt
CrashMail to your platform. The amount of work required mostly depends on whether
your C-compiler supports some common POSIX-functions which CrashMail uses.

View File

@ -0,0 +1,114 @@
Description of CrashMail's built-in AreaFix
===========================================
What is AreaFix?
----------------
AreaFix is a feature present at most FidoNet nodes, either built-in in
the tosser or as a stand-alone program. AreaFix allows you to connect
and disconnect to echomail areas, change your password and change some
other things in your configuration without asking your feed/boss to do
it for you.
How do I talk to AreaFix?
-------------------------
You communicate with AreaFix using netmail messages. The message header
of a message to AreaFix should look like this:
From: Johan Billing
To: AreaFix
Subj: <password> [<switches>]
<AreaFix commands>
...
---
<Password> is your private AreaFix password that you need to make sure
that nobody else alters your configuration. Your AreaFix password is
assigned to you by your boss/feed, so you may have to ask him about a
password.
[<switches>] are extra commands that you can send to AreaFix. Currently
there is only one switch:
-l or -q Send list of all areas
This switch is only here to be compatible with other AreaFix programs.
It is recommended that you use the %-commands described later instead.
"---" marks the end of an AreaFix message.
NOTE: The name doesn't necessarily have to be AreaFix, your boss may have
configured CrashMail to use other names instead.
What commands can I put in the text?
------------------------------------
Change connected areas:
[+]areaname[,R=<max>] Connect to an area. The '+' is optional. If
the R option is specified after the area,
the specified number of old messages in the area
will be rescanned and sent to you.
-areaname Disconnect from an area
=areaname[,R=<max>] Update. You can use this to rescan an area which you
already are connected to.
Special commands
%HELP Send this text
%LIST Send list of all areas
%QUERY Send list of all linked areas
%UNLINKED Send list of all unlinked areas
%PAUSE Do not send any echomail until a %RESUME is sent
%RESUME Send echomail again. These commands can be useful
if you are away for a few weeks and don't want to
get any echomail.
%PWD <pw> Changes your AreaFix password to the new password
specified after the command.
%COMPRESS <name> Changes the packer used to compress your mail to
the packer specified after the command. Send
"%COMPRESS ?" to get a list of packers.
%RESCAN All areas that are added or updated after this
line will be rescanned, that is all old messages
in those areas will be sent to you. This can be
very dangerous since you don't know how many
messages you will get so in most cases, it is
better to use the R option when adding/updating
areas instead.
Examples:
=========
R20_TRASHCAN Connect to R20_TRASHCAN
%LIST Send list of areas
R20_AMIGA,R=50 Connect to R20_AMIGA and get the last 50 messages
in the area.
%PWD xyzzy Change your AreaFix password to "xyzzy".
%COMPRESS ZIP Change your compression method to ZIP.
%PAUSE Turn off echomail for a while
%RESUME Turn on echomail again
=R20_AMIGA,R=100 Get the last 100 messages in R20_AMIGA (if you are
already connected to the area)
A few words on rescan
=====================
Messages that are rescanned might not look exactly like they originally did
because of the way they are stored locally. When messages are rescanned from
a JAM messagebase, all control lines ("kludges") will be at the beginning of
the message regardless of where they originally were. You can easily tell if
a message has been rescanned, just look for the RESCANNED control line.

View File

@ -0,0 +1,505 @@
CrashMail II
The Next Generation!
...a stranger in a strange land...
============
Introduction
============
Welcome to CrashMail II! CrashMail II is basically a more portable version
of CrashMail, my tosser for Amiga computers. Users of the old Amiga
version will probably find some things familiar while some features are
gone such as the ARexx port (for obvious reasons!) and the GUI
configuration editor. The only feature that CrashMail II has and the old
CrashMail hasn't is support for JAM messagebases. (By the way, I have also
written a tick file processor called CrashTick for the Amiga. If someone
wants to port it, contect me and I'll give you the source.)
For suggestions, bug reports and questions, don't hesitate to contact me at:
billing@df.lth.se
=========
Copyright
=========
Copyright (C) 1998-2004, Johan Billing <billing@df.lth.se>
Copyright (C) 1999-2010, Peter Krefting <peter@softwolves.pp.se>
Copyright (C) 2009-2013, Robert James Clay <jame@rocasa.us>
Copyright (C) 2013, Lars Kellogg-Stedman <lars@oddbit.com>
JAMLIB is copyright (c) 1999 Björn Stenberg. JAMLIB is released under the
GNU Lesser General Public License, See src/jamlib/jamlib.doc for more
information.
Except where explicitly stated otherwise, all other parts of CrashMail are
copyright 1998-2004 Johan Billing. Permission to use, copy and distribute
CrashMail is granted provided that this copyright notice is included. Permission
to modify CrashMail is granted. Distributing modified versions of CrashMail is
allowed provided that the documentation clearly states that it is a modified
version. Parts of CrashMail may be freely used in other projects as long as
the documentation mentions the original copyright holder.
================
Acknowledgements
================
Many thanks to Björn Stenberg for creating the excellent subroutine library
JAMLIB which CrashMail uses for handling JAM messagebases.
Thanks for Peter Karlsson for porting CrashMail II to OS/2 and the man pages.
=============
Documentation
=============
The documentation is very brief and CrashMail probably isn't the ideal
choice for Fidonet beginners. All documentation of the available keywords
in the configuration file can be found in the example crashmail.prefs file.
Some other items about CrashMail that are worth mentioning can be found in
the section below.
Items that need to be discussed
===============================
Platforms
---------
This version of CrashMail can be compiled for Win32, Linux and OS/2. If you
are interested in running CrashMail on another platform, please contact me if
you are willing to do the work necessary to adapt CrashMail to your platform.
The amount of work required mostly depends on whether your C-compiler supports
some common POSIX-functions which CrashMail uses.
Some notes on different platforms:
Win32 & OS/2
If you want to use an old reader that only can handle 8+3 filenames,
you have to use %8 in the path of your DEFAULT area if you are using
the auto-add feature. This creates an 8 digit serial number to use as
the path for the area. Note that if CrashMail is run twice in a short
period of time (a few seconds), it might create duplicate paths. Avoid
%8 if it is at all possible.
Linux
Don't use the ~ character in paths. Such paths are expanded to point
to your home directory by the shell and not by the i/o functions in
the system. They will not work in CrashMail.
In *.msg areas, make sure that all files are named *.msg and not *.MSG!
If they are not named in lowercase, CrashMail will not export them.
As an extra bonus, the Linux version of CrashMail can use the syslog instead
of using its own log file. Just use "syslog" as the name of your log file.
If the precompiled binaries in the CrashMail archive don't work on your
system, you will have to compile your own. See INSTALL for more
information about this.
Arguments
---------
Available arguments for CrashMail:
SCAN
Scan all areas for messages to export.
TOSS
Toss all .pkt files and bundles in inbound directory.
TOSSFILE <string>
Toss the specified file.
TOSSDIR <string>
Toss all files in the specified directory.
SCANAREA <string>
Scan the specified area.
SCANLIST <string>
Scan all areas listed in the specified file.
SCANDOTJAM <string>
Scan all areas listed in an echomail.jam/netmail.jam file. The main difference
between SCANDOTJAM and SCANLIST is that a *.jam file contains the paths to the
messagebases instead of tagnames. Areas are only scanned once even if listed
multiple times.
RESCAN <string>
RESCANNODE <string>
RESCANMAX <string>
Rescans the specied area for the specied node. If RESCANMAX is specified,
it sets the maximum number of messages to rescan.
SETTINGS <string>
Use this configuration file instead of the default. You can use the
environment variable CMCONFIGFILE to set the default configuration file.
VERSION
Show version information about CrashMail.
LOCK
Locks CrashMail's configuration file and then exits. CrashMail has a simple
locking mechanism to ensure that two instances of CrashMail never use the
same configuration file at the same time. You can use this if you want to
temporarily want to stop CrashMail from running, e.g. when updating the
nodelist.
UNLOCK
Removes the lock on CrashMail's configuration file. Only use this when the
configuration file previously has been locked with LOCK, otherwise terrible
things might happen.
NOSECURITY
Process all packets without security checks. This is intended to be used
mainly with TOSSDIR/TOSSFILE and with packets created by CrashWrite.
Support programs
----------------
crashexport <crashmail.prefs> <output file> <format> [GROUP <groups>]
This command reads a CrashMail configuration file and creates an arealist.
If the GROUP keyword is used, only areas in the specified groups are
included. CrashExport can create lists in these formats:
AREASBBS
A standard areas.bbs file that can be read by many programs
FORWARD
A list of areas that can be used for forward-requests on other nodes.
The file is a pure ASCII file where each line contains the name of the
area and its description.
FORWARDNODESC
Same as FORWARD but without area descriptions.
GOLDED
Creates an area configuration file in GoldED format.
TIMED
Creates an area configuration file in timEd format.
crashstats <statsfile> [SORT <mode>] [LAST7] [NONODES] [NOAREAS]
This command displays the statistics file created by CrashMail. With the
SORT keyword you can specify these sort modes:
a Sort alphabetically
t Sort by total number of messages
m Sort by msgs/day
d Sort by first time messages were imported
l Sort by last time messages were importd
u Sort by number of dupes
With LAST7, you can see detailed information about the flow of messages in
area areas for the last seven days. With NONODES and NOAREAS you can decide
to hide node or area statistics.
crashlist [<dir>]
Builds an index for the nodelists in the specified directory (or in the
current directory if no directory is specified). To find out what
nodelists to read, CrashList uses a file called cmnodelist.prefs in the
nodelist directory. The format of this file is as follows:
<nodelist name> [<default zone>]
As the name of the nodelist, you can either specify the full name of the
nodelist or just the base name of the nodelist (without .xxx at the end).
If you just specify the base name, CrashList will use the latest nodelist
with that name (selected by date, not the extension). A default zone can
be used for regional nodelists without a Zone line. All lines beginning
with a semicolon are treated as comments. Pointlists should be in
BinkleyTerm format and should be specified after the real nodelists.
Example cmnodelist.prefs:
; Configuration for CrashList
;
; Format: <nodelist> [<default zone>]
NODELIST
BTPOINT
crashgetnode <node> [<nodelist dir>]
Looks up the specified node in the nodelist and prints the information
that was found. If no nodelist directory is specified, CrashGetNode uses
the path specified in the environment variable CMNODELISTDIR.
crashmaint [MAINT] [PACK] [VERBOSE] [SETTINGS <filename>] [PATTERN <pattern>]
Deletes old messages according to KEEPNUM and KEEPDAYS in crashmail.prefs. The
program can do two different operations on a messagebase, MAINT and PACK. The
meaning of these two modes are different for different messagebase formats.
*.msg
MAINT deletes messages and PACK renumbers the area.
JAM
MAINT sets the Deleted flag for the messages. PACK removes all messages with
the Deleted flag from the messagebase.
Both MAINT and PACK can be specified at the same time. You can specify a
config file other than the default with the SETTINGS keyword (use the
environment variable CMCONFIGFILE to set the default configuration file).
Using the PATTERN keyword, you can perform the operations on only some of your
areas. VERBOSE gives you a lot of information which you don't really need.
Example: crashmaint MAINT PACK PATTERN R20_AMIGA*
crashwrite DIR <directory> ...
CrashWrite reads a text file and creates a .pkt file that can be processed
by CrashMail. This can be used to post announcements and other messages in
areas. The best way to use CrashWrite is to let it generate packets in a
separate directory and then toss them with TOSSDIR NOSECURITY.
There are many keywords for CrashWrite. All keywords are optional except for
DIRECTORY. If you do not enter a keyword, a default value will be used.
FROMNAME <string>
FROMADDR <node>
TONAME <string>
TOADDR <node>
SUBJECT <string>
Use these keywords to set the header of the message. You only need to enter
TONAME and TOADDR for netmails.
PKTFROMADDR <string>
PKTTOADDR <string>
Use these if you want to set the origin and destination address of the packet
to something other than the origin and destination address of the message
inside the packet. If you do not specify these keywords, FROMADDR and
TOADDR will be used for the packet as well.
PASSWORD <string>
You can use this keyword to set a password for the packet. The maximum
length of the password is eight characters.
AREA <area>
The area the message should be posted in. If you do not enter an area, the
message will be sent as a netmail.
ORIGIN <origin>
The origin line for the message. This keyword has no effect for netmail
messages.
DIR <dir>
The directory where the packet should be placed.
TEXT <filename>
The name of a text file that should be included as the message text.
NOMSGID
Prevents CrashWrite from adding a MSGID line.
FILEATTACH
Sets the file-attach flag for netmails. The filename should be put in the
subject line.
crashlistout <directory> [<zone>] [<pattern>] VERBOSE
This command lists the contents of a outbound directory. Use zone to specify
which zone the directory is for (the default is 2). It is possible to only
list files for nodes that match a specified pattern. If you use the VERBOSE
switch, crashlistout will also list the contents of any *.req and flow files.
Paths
-----
You should always use absolute paths in crashmail.prefs, otherwise CrashMail
will fail to unpack incoming bundles. If you use relative paths, CrashMail
will also use relative paths in flow files which might confuse your mailer.
Outbound
--------
CrashMail uses a 5D BinkleyTerm outbound. If there is a demand for FrontDoor
style outbounds (*.msg based), it might be implemented in a future version.
Messagebase formats
-------------------
CrashMail currently can use *.msg messagebase and JAM messagebases.
Some notes on the different messagebase formats:
*.msg
*.msg is the most basic format for Fidonet messages. It is specified in
FTS-0001 and most Fidonet programs can handle this. There are however some
variations. There are Zone and Point fields in the message header, but
since some programs use them for other purposes, CrashMail doesn't read
them. This means that CrashMail won't work if your reader doesn't create
INTL, TOPT and FMPT kludge lines. Most readers do so this probably won't
be a problem.
JAM
JAM is a newer messageformat which while not perfect at least is much
better than *.msg. It provides reply-linking, but unfortunately not
between areas. JAM has a few odd features which CrashMail does not
support. CrashMail will not create TRACE fields from Via kludges, it
does not support messages with multiple recipients (carbon copies) and
it does not support file-attaches with wildcards, indirect file-attaches
or file-attaches with aliases. CrashMail also handles only one attached
file/file request per message.
Highwater marks
---------------
CrashMail can use highwater marks to speed up the exporting of messages. The
highwater mark is only the number of the highest exported message in an area.
If you decide to use highwater marks, CrashMail will only export messages
with a message number that is higher that the old highwater mark. If you want
to export messages with a lower number than the highwater mark, you have to
force CrashMail to scan the whole area by deleting the file where the
highwater mark is stored. In *.msg areas the highwater mark is stored in the
first message of the area (1.msg) and in JAM areas it is stored in the
<basename>.cmhw file. (Also note that this is why the first message in a
*.msg area never is exported.)
Nodelists
---------
CrashMail can use two nodelist formats:
1) Its own nodelist format ("CMNL"). The format consists of a rather simple
index which is created by the program CrashList. See the descriptions of
CrashList and CrashGetNode for more information.
2) A nodelist in the Version7+ format ("V7+") used by BinkleyTerm and other
programs.
Patterns
--------
String patterns
String patterns are rather primitive in CrashMail. There are two available
wildcards, ? and *. ? matches any character and * matches the rest of the
string. ab*, ab*de and ab*de* are therefore equivalent and all match all
strings beginning with ab. String patterns are used for robot names, remap
names etc.
Node patterns
CrashMail has very powerful pattern matching for nodes. "*" and "?" can
be used as wildcards and there a special keywords that matches all nodes
that belongs to a zone, region, net, hub or a node.
2:200/207.*
This would match 2:200/207.1, 2:200/207.2, 2:200/207.42 etc
2:200/2*.*
This would match 2:200/213.99, 2:200/224.48, 2:200/207.0 etc.
This would NOT match 2:200/103.42.
2:200/2?.*
This would match 2:200/24.42, 2:200/25.52 but not 2:200/200.0.
2:*/100.0
This would match 2:200/100.0, 2:200/100.0, 2:300/100.0 etc.
ZONE 2
This matches everything in zone 2. This has the same effect as 2:*/*.*.
REGION 2:20
This matches everything in region 2:20. You can only use the REGION
keyword if you use a nodelist.
NET 2:200
Matches everything in net 2:200. This is the same as 2:200/*.*.
HUB 2:205/300
Matches all node that belongs to the hub 2:205/300. You can only use
the HUB keyword if you use a nodelist.
NODE 2:200/108
Matches the node 2:200/108 and all its points. This does exactly the
same as 2:200/108.*.
*:*/*.*
This would match everything.
Destination node patterns
These are a bit more complicated since the destination node of the
operation is also involved. This is best explained with netmail routing
as an example. In CrashMail, destination node patterns are also used
in the remap function, but it works very similarly there.
*:*/*.0, netmail for 2:200/108.7
This netmail would be routed to 2:200/108.0
*:*/0.0, netmail for 2:200/108.7
This netmail would be routed to 2:200/0.0
ZONE, netmail for 2:201/274
This netmail is routed to the Zone Coordinator, in this case 2:2/0.
REGION, netmail for 2:200/207.5
This netmail is routed to the Region Coordinator, in this case 2:20/0.
You can only use this keyword if you use a nodelist.
NET, netmail for 2:200/108.7
This netmail is routed to the host of the net, in this case 2:200/0.
This is the same as *:*/0.0
HUB, netmail for 2:200/108.7
This netmail is routed to the hub of the node, in this case 2:200/100.
You can only use this keyword if you use a nodelist.
NODE, netmail for 2:200/108.7
This netmail is routed to the boss of the point, in this case 2:200/108.0.
This is equivalent to *:*/*.0.
*:*/*.*, mail for 2:203/699.0
This would be routed to 2:203/699.0

View File

@ -0,0 +1,714 @@
; Example configuration file for CrashMail II
;
; This file demonstrates all keywords you can use in the configuration file.
;
; General configuration
; =====================
;
; SYSOP <name>
;
; This keyword lets you configure the name of the system operator. It is used
; as the sender name of all messages that CrashMail generates. (Bounce
; messages, receipts, AreaFix responses.) Max 36 characters.
SYSOP "Johan Billing"
; LOGFILE <filename>
; LOGLEVEL <level>
;
; Here you can configure the logging in CrashMail. CrashMail will write all
; log messages with a level lower than the level configured here both to the
; console and to the specified file.
;
; The following loglevels exist:
;
; 1 Minimum
; 2 Small
; 3 Normal
; 4 Extra
; 5 Extreme
; 6 Debug
;
; In the Linux version of CrashMail, it is possible to enter "syslog" as the
; filename. If you do this, everything will be logged to the syslog instead.
LOGFILE "c:\\fido\\logs\\crashmail.log"
LOGLEVEL 5
; DUPEFILE <filename> <maxnumber>
; DUPEMODE BAD/KILL/IGNORE
;
; Here the file that CrashMail uses for its duplicate detection is specified.
; Maxnumber is the maximum number of the messages that should be stored in the
; dupe buffer. Each message in the dupe buffer consumes 8 bytes of RAM and on
; average about 40 bytes of disk space.
;
; These are the available modes for dupe checking:
;
; BAD Dupes are moved to the BAD area
; KILL Dupes are killed
; IGNORE No dupechecking
DUPEFILE "c:\\fido\\logs\\crashmail.dupes" 200
DUPEMODE BAD
; LOOPMODE IGNORE/LOG/LOG+BAD
;
; Loop-mails are netmails that are routed between two systems in an infite
; loop. CrashMail can detect such mails by checking if you system is already
; listed in the ^Via lines of the message. This keyword decides what
; CrashMail should do when such a message is encountered.
;
; IGNORE do nothing at all
; LOG CrashMail logs that it has encountered a loop-mail.
; LOG+BAD CrashMail logs the loop-mail and imports a copy to your BAD area.
; Only the kludges are imported to preserve privacy.
LOOPMODE LOG+BAD
; MAXPKTSIZE <maxsize>
; MAXBUNDLESIZE <maxsize>
;
; Here you can configure the maximum size of the .pkt files and bundles that
; CrashMail generates. If a file grows bigger than this limit, CrashMail
; starts a new bundle/pkt instead. The limits are in KB.
MAXPKTSIZE 50
MAXBUNDLESIZE 100
; DEFAULTZONE <zone>
;
; If CrashMail can't figure out the zone of a message in another way, the
; zone configured here is used.
DEFAULTZONE 2
; NODELIST <path> <type>
;
; This is the nodelist that CrashMail should use. To see the supported
; nodelist formats, type "crashmail version". The meaning of path may
; be different for different nodelist formats.
; Paths
; =====
;
; INBOUND <directory>
;
; The inbound directory is the directory where CrashMail looks for .pkt files
; and bundles to toss.
INBOUND "c:\\fido\\inbound"
; OUTBOUND <directory>
;
; The outbound directory is where CrashMail writes the flow files that tells
; the mailer what files to send.
OUTBOUND "c:\\fido\\outbound"
; TEMPDIR <directory>
;
; This is the directory where CrashMail unpacks incoming bundles.
;
TEMPDIR "c:\\fido\\temp"
; CREATEPKTDIR <directory>
;
; This is the directory where CrashMail stores created .pkt files until they
; are stored in the packet directory.
CREATEPKTDIR "c:\\fido\\temp"
; PACKETDIR <directory>
;
; This is the directory where CrashMail stores generated bundles.
PACKETDIR "c:\\fido\\packets"
; STATSFILE <filename>
;
; This is the file where CrashMail stores statistics about areas and nodes.
; You can display the contents of this file with CrashStats.
STATSFILE "c:\\fido\\crashmail.stats"
; BEFORETOSS <command>
;
; CrashMail will execute this command before a *.pkt file is tossed. You can
; use %f for the filename of the packet. CrashMail will abort tossing if this
; command returns an error.
;BEFORETOSS "cp %f /fido/toss-backup"
; BEFOREPACK
;
; CrashMail will execute this command before a *.pkt file is added to an
; archive. You can use %f for the filename of the packet. If the command
; fails, CrashMail will try again the next time it processes the outbound
; directory.
;BEFOREPACK "cp %f /fido/pack-backup"
; Switches
; ========
;
; STRIPRE
;
; CrashMail should strip all occurences of "Re:", "Re[x]:" and "Re^x:"
; in the subject of messages before they are imported.
;
STRIPRE
; FORCEINTL
;
; CrashMail should add an INTL line to all messages even when the sender
; and the destination are in the same zone.
FORCEINTL
; NOROUTE
;
; CrashMail should never route netmails and just import them instead.
NOROUTE
;
; ANSWERRECEIPT
;
; CrashMail should honor receipt requests.
;
ANSWERRECEIPT
; ANSWERAUDIT
;
; CrashMail should honor audit requests.
;
ANSWERAUDIT
; CHECKSEENBY
;
; CrashMail should never send echomail to nodes that already are in the
; SEEN-BY lines.
CHECKSEENBY
; CHECKPKTDEST
;
; CrashMail should check the destination node of all incoming .pkt files and
; only toss them if they are adressed to one of the local AKAs.
;CHECKPKTDEST
; PATH3D
;
; CrashMail also adds points to ^PATH lines. Not always a good idea since it
; is not allowed in the echomail standard.
PATH3D
; IMPORTEMPTYNETMAIL
;
; Some mailers like FrontDoor like to send meaningless empty netmails with
; no text. Spefify this options if you for some reason want to import such
; mails.
;IMPORTEMPTYNETMAIL
; IMPORTAREAFIX
;
; Use this if you want messages to CrashMail's internal AreaFix to be
; imported to your netmail area.
IMPORTAREAFIX
; NODIRECTATTACH
;
; Normally CrashMail changes all netmail messages with attached file to
; direct status. Use this to turn off this behaviour.
;NODIRECTATTACH
; BOUNCEPOINTS
;
; Use this to bounce netmail messages to non-existing points with one of
; your AKAs as boss.
;BOUNCEPOINTS
; IMPORTSEENBY
;
; Use this if you want to import the SEEN-BY lines.
IMPORTSEENBY
; AREAFIXREMOVE
;
; Use this to allow the AreaFix to remove areas when the last downlink
; unsubscribed.
AREAFIXREMOVE
; WEEKDAYNAMING
;
; Name bundles according to the day of the week they are created.
WEEKDAYNAMING
; ADDTID
;
; Add a ^TID line to all messages exported by CrashMail.
ADDTID
; ALLOWRESCAN
;
; Allow nodes to rescan areas in the AreaFix.
ALLOWRESCAN
; FORWARDPASSTHRU
;
; Make areas created when they were forward-requested by a downlink pass-thru
; rather than importing them to your messagebase.
;FORWARDPASSTHRU
; BOUNCEHEADERONLY
;
; Only write the header and do not include message text when messages are
; bounced.
;BOUNCEHEADERONLY
; REMOVEWHENFEED
;
; CrashMail should remove areas when the feed unsubscribes to them. AreaFix
; messages or notification messages can be sent to your downlinks, see the
; Node configuration.
;REMOVEWHENFEED
; INCLUDEFORWARD
;
; Include all forward-requestable areas in the area lists generated by the
; AreaFix.
INCLUDEFORWARD
; NOMAXOUTBOUNDZONE
;
; CrashMail normally puts outgoing mail for all zones >4095 in the outbound
; directory for zone 4095 (usually outbound.fff). If this switch is turned
; on, CrashMail will use separate outbound directories also for zones >4095.
; The background of this option is that the Binkley outbound style originated
; on platforms where file names were limited to 8+3 characters. For
; compatibility with many older mailers, leave this switch turned off.
; There are however some mailers that also expect to find mail for zones
; >4095 in separate outbound directories.
;NOMAXOUTBOUNDZONE
; ALLOWKILLSENT
;
; If this option is used, CrashMail will delete all netmail messages with
; the killsent flag after they have been expored
;ALLOWKILLSENT
; FLOWCRLF
;
; If this option is used, CrashMail writes CRLF as the end-of-line character
; in flow files instead of just LF. Apparently some mailers need this.
;FLOWCRLF
; NOEXPORTNETMAIL
;
; If this option is used, CrashMail will skip netmail areas when using the
; SCAN or SCANLIST arguments. Use this if you want to use another program
; to handle netmail.
;NOEXPORTNETMAIL
; Groupnames
; ==========
;
; GROUPNAME <letter> <description>
;
; Here you can describe you groups. These descriptions are used in the area
; lists created by the AreaFix.
GROUPNAME A "Molia"
GROUPNAME H "Lokala"
; Bounce
; ======
;
; BOUNCE <pattern1> <pattern2> ...
;
; Bounce messages that match one of these pattern if the destination node
; doesn't exist in the nodelist. This only works if you use a nodelist with
; CrashMail. You can have multiple BOUNCE lines.
BOUNCE "1:*/*.*" "2:*/*.*" "3:*/*.*" "4:*/*.*" "5:*/*.*" "6:*/*.*"
; Fileattach
; ==========
;
; FILEATTACH <pattern1> <pattern2> ...
;
; CrashMail will refuse to route files to nodes that are not configured
; here and will send a bounce messages. Multiple FILEATTACH lines are
; allowed.
FILEATTACH "2:200/207.5"
; Change
; ======
;
; CHANGE <old flavour> <pattern> <new flavour>
;
; CrashMail can change the flavour (also known as priority) of netmail. Note
; that this does not affect echomail.
;CHANGE * 2:200/207.5 Hold
;CHANGE Normal,Direct 2:200/*.* Crash
; Packers
; =======
;
; PACKER <name> <pack command> <unpack command> <recog>
;
; Here you configure the external packers that CrashMail uses. %a stands for
; archive name and %f stands for file name. The recog string is used when
; CrashMail detects the packer used to pack a bundle. If the beginning of
; the bundle matches the recog string, CrashMail uses that packer. ? can be
; used as a wildcard and you can use $xx to specify a hexadecimal number.
PACKER "LHA" "c:\\fido\\bin\\lha a %a %f" "c:\\fido\\bin\\lha x %a" "??-lh?-"
PACKER "ZIP" "c:\\fido\\bin\\pkzip %a %f" "c:\\fido\\bin\\pkunzip %a" "PK"
; AKA
; ===
;
; AKA <node>
; DOMAIN <domain>
; ADDNODE node1 node2 ...
; REMNODE nodepattern1 nodepattern2 ...
;
; Here you configure the adresses of your node. ADDNODE is used to add nodes
; the the SEEN-BY lines in areas with this AKA and REMNODE is used to remove
; nodes. Nodes for ADDNODE and REMNODE has to be 2D, that is only net/node
; should be specified. Patterns are allowed for REMNODE.
AKA 2:200/207.6
DOMAIN "FidoNet"
AKA 2:200/108.7
DOMAIN "FidoNet"
; Nodes
; =====
;
; NODE <node> <packer name> <packet password> [<flags>]
; PKTFROM <node>
; AREAFIXINFO <areafix password> <groups> <read-only groups> <add groups>
; DEFAULTGROUP <group>
; REMOTEAF <areafix name> <areafix password> [NEEDSPLUS]
; REMOTESYSOP <name>
;
; These are the nodes you interchange mail with. You can only send echomail
; to nodes specified here, but netmail can also be sent to other nodes.
;
; If PKTFROM is used, the node specified there will be used as the originating
; node in all packet files sent to this node.
;
; The groups decide what areas a node may subscribe to in the AreaFix. If the
; area is in one of the read-only groups, the node will be added as read-only.
; If a new area is added in one of the add groups, this node will automatically
; be subscribed to it. The default group is the group used for areas that are
; autoadded from this node.
;
; REMOTEAF and REMOTESYSOP are used when CrashMail needs to send messages to
; the AreaFix or the sysop of this node. Use NEEDSPLUS if the remote AreaFix
; needs commands wants "+area" when subscribing to new areas instead of just
; "area".
;
; The following flags can be set for a node:
;
; NOTIFY
;
; When a SENDQUERY, SENDLIST, SENDUNLINKED, SENDINFO or SENDHELP with the
; argument ALL is used on the command-line, messages will be sent to all
; nodes with this flag set.
;
; PASSIVE
;
; Echomail is never sent to this node. Used for the %PAUSE and %RESUME
; commands in the AreaFix.
;
; NOSEENBY
;
; No SEEN-BY lines are included in messages sent to this node. Should
; normally not be used.
;
; TINYSEENBY
;
; Only sender and destination is included in SEEN-BY lines in messages
; sent to this node. Should normally not be used.
;
; FORWARDREQ
;
; This node is allowed to do forward-requests.
;
; PACKNETMAIL
;
; Netmail to this node should be packed along with the echomail.
;
; SENDAREAFIX
;
; AreaFix disconnect requests should be sent to this node when the feed
; unsubscribes from an area.
;
; SENDTEXT
;
; Notification messages should be sent to the sysop of this node when the
; feed unsubscribes from an area.
;
; AUTOADD
;
; New areas from this node should be auto-added to the configuration. If
; auto-add is not set, the areas will still be added but with an UNCONFIRMED
; line.
;
; CRASH
;
; Send echomail to this node with priority Crash.
;
; DIRECT
;
; Send echomail to this node with priority Direct.
;
; HOLD
;
; Send echomail to this node with priority Hold.
;
NODE 2:200/100.0 "ZIP" "" PACKNETMAIL AUTOADD
DEFAULTGROUP A
NODE 2:201/128.0 "ZIP" "" PACKNETMAIL AUTOADD
DEFAULTGROUP B
NODE 2:200/207.5 "LHA" "secret" NOTIFY FORWARDREQ PACKNETMAIL AUTOADD
AREAFIXINFO "secret" "" "" ""
REMOTESYSOP "Johannes Nilsson"
; AreaFix
; =======
;
; AREAFIXHELP <filename>
;
; The file that is sent when a downlink issues a %HELP command.
AREAFIXHELP "c:\\fido\\AreafixHelp.txt"
; AREAFIXMAXLINES <max>
;
; The maximum number of lines in an AreaFix response. CrashMail splits the
; response if it exceeds this number.
;
AREAFIXMAXLINES 50
; AREAFIXNAME <name>
;
; A name that CrashMail's AreaFix should respond to.
AREAFIXNAME "AreaFix"
AREAFIXNAME "AreaMgr"
AREAFIXNAME "CrashMail"
; AREALIST <node> <file name> [GROUP <group>] [FORWARD] [DESC]
;
; This is a list of the areas that are available at a node. It should contain
; lines with the format "<tagname> <description>". If DESC is specified,
; descriptions are taken from this file when CrashMail auto-adds areas. If
; FORWARD is specified, this file is used to determine what files are
; available for forward-requests. GROUP specifies the group needed to be
; allowed to forward-requests areas in this list.
AREALIST 2:200/100.0 "c:\\fido\\lists\\R20Desc.lst" GROUP A FORWARD DESC
; Routing
; =======
;
; ROUTE <pattern> <destination pattern> <aka>
;
; Netmail messages with a destination that match the pattern are routed to
; the destination pattern using the specified AKA. See descriptions of how
; patterns work elsewhere.
ROUTE "2:200/207.5" "2:200/207.5" 2:200/108.7
ROUTE "2:200/*.*" "2:200/100.0" 2:200/108.7
ROUTE "*:*/*.*" "2:201/128.0" 2:200/108.7
; MSG
; ===
;
; MSG_HIGHWATER
;
; Use 1.msg as highwater mark in *.msg areas.
MSG_HIGHWATER
; MSG_WRITEBACK
;
; Overwrite the old message with the new message when it is imported instead
; of just changing the SENT flag. Use this to see the new SEEN-BY:s and PATH
; in the messagebase.
;MSG_WRITEBACK
; JAM
; ===
;
; JAM_HIGHWATER
;
; Use highwater marks to speed up scanning. The highwater mark is stored in
; a file called <basename>.cmhw.
JAM_HIGHWATER
; JAM_LINK
;
; Do reply-linking based on MSGID and REPLY after import.
JAM_LINK
; JAM_QUICKLINK
;
; Just compare the CRC of MSGID/REPLY when linking and don't read the strings
; from the messagebase. This makes linking quicker, but messages that don't
; match may be linked by mistake.
;
JAM_QUICKLINK
; JAM_MAXOPEN <max>
;
; This is the number of JAM messagebases that CrashMail keeps open at a time.
; A higher number speeds up tossing, but since CrashMail keeps four files
; open for each area, don't use a too high number if you only can have a
; limited number of files open...
JAM_MAXOPEN 5
; Filter
; ======
;
; CrashMail has a message filter that can be used for filtering out messages
; that match the specified criteria and perform a number of commands on them.
; See file doc/filter.txt for a complete description of the message filter.
;
; General syntax:
;
; FILTER <expression>
; <command 1>
; <command 2>
; ...
;FILTER SOURCE=TOSSED and TYPE=ECHOMAIL and TONAME="Johan Billing"
;COPY PERSONAL_MESSAGES
; Areas
; =====
;
; AREA/NETMAIL/LOCALAREA <tagname> <aka> [<messagebase> <path>]
; IMPORT/EXPORT <node1> <node2> ...
; BANNED <node1> <node2> ...
; DESCRIPTION <desc>
; GROUP <group>
; KEEPNUM <num>
; KEEPDAYS <num>
; UNCONFIRMED
; MANDATORY
; DEFREADONLY
; IGNOREDUPES
; IGNORESEENBY
;
; Here you configure all areas that CrashMail knows. Area definitions begin
; with AREA for echomail areas and NETMAIL for netmail areas. Local areas
; defined with LOCALAREA are not used by CrashMail, but are included in
; config files created by CrashExport and are maintained when running
; CrashMaint.
;
; To see the supported messagebase formats in your version of CrashMail,
; type "crashmail version". What path should be used depends on the used
; messagebase formats.
;
; Netmail messages addressed to the Aka or to one of the nodes specified on
; an IMPORT line are imported in netmail areas. Echomail areas cannot have
; an IMPORT line but instead has one or more EXPORT lines where the nodes
; that this area should be sent to are listed. Each node on an export line
; has the format "[<modifier>]<node>" where modifier may be !, @ or %.
; ! means that the node is read-only, @ means that the node is write-only
; and % means that the node is the feed for this area.
;
; Note that nodes on the EXPORT line may be abbreviated. And example:
;
; EXPORT 2:2/2 1 .5 3/2 .22 3 .33
;
; will be expanded to
;
; EXPORT 2:2/2 2:2/1 2:2/1.5 2:3/2 2:3/2.22 2:3/3 2:3/3.33
;
; Nodes in the BANNED line may not subscribe to this area with the AreaFix.
; MANDATORY means that nodes may not unsubscribe from this area in the
; AreaFix. DEFREADONLY means that nodes that subscribe to this area in the
; AreaFix will be added as read-only.
;
; Areas with UNCONFIRMED are areas that have been auto-added by CrashMail
; but not yet confirmed. Areas get this flag when the node didn't have the
; flag AUTOADD set. CrashMail treats unconfirmed areas as if they didn't
; exist at all.
; KEEPNUM and KEEPDAYS are used by CrashMaint to decide how long messages
; should be kept in the messagebase.
;
; An area with the tagname BAD is a special area that are used for messages
; that for some reason are considered "bad" by CrashMail.
;
; Another special kind of areas are the default areas. When CrashMail adds
; an area, it searches for a default area to use as a template. First it
; looks for an area named DEFAULT_<groups> where <groups> contains the group
; of the new area. If such an area doesn't exist, it looks for an area called
; DEFAULT. If a default area was found, CrashMail copies this configuration
; for this area to the new area. In the path of the default area, you can
; use the following %-codes:
;
; %a Name of the area
; %l Name of the area in lowercase letters
; %8 Eight digit serial number
;
; You must use one of these %-codes or the new path will not be unique.
NETMAIL "NETMAIL" 2:200/108.7 JAM "c:\\fido\\areas\\NETMAIL"
AREA "BAD" 2:200/108.7 JAM "c:\\fido\\areas\\BAD"
AREA "DEFAULT_A" 2:200/108.7 JAM "c:\\fido\\areas\\%8"
AREA "R20_INTRESSE" 2:200/108.7 JAM "c:\\fido\\areas\\36124179"
EXPORT %2:200/100.0
DESCRIPTION "Intresseklubben"
GROUP A
AREA "R20_TRASHCAN" 2:200/108.7 JAM "c:\\fido\\areas\\3612417a"
EXPORT %2:200/100.0
DESCRIPTION "Soptunnan"
GROUP A

View File

@ -0,0 +1,296 @@
Description of the message filter in CrashMail II
=================================================
Introduction
------------
The message filter makes it possible filter out messages that match a set of
critera and perform a number of commands on them. All messages that are handled
by CrashMail are checked against the filter statements in the configuration.
Filter statements have this general syntax in the configuration:
FILTER <expression>
<command 1>
<command 2>
...
This file will start by describing how expressions work and what variables
you can use in them and then continue by describing the available commands.
This file relies heavily on examples to describe how the filter works.
Expressions
-----------
Expressions have this general syntax:
<variable><operator><pattern>
CrashMail understands the operator "=" for all variable types expect text
variables and also "|"(substring search) for string and text variables.
Boolean variables can be used without an operator in which case "variable"
equals "variable=TRUE". You cannot have space characters around the operator,
CrashMail will not understand for example "FILEATTACH = TRUE".
A few examples:
TONAME="Johan Billing"
SUBJECT=CrashMail
TEXT|"CrashMail"
TOLOCALAKA
If the variable matches the pattern, the expression is TRUE and the commands
for the filter will be performed. You can also use NOT to negate a statement
and perform the commands if the expression is not true:
NOT FROMNAME="AreaFix"
Expressions can be linked using AND and OR. Parentheses can be used to set
the evaluation order. (Default is evaluation from left to right.) Examples:
TYPE=NETMAIL and TOLOCALAKA and TONAME=Raid
TYPE=ECHOMAIL and (TONAME="Johan Billing" or TONAME="Billing Johan")
TYPE=NETMAIL and NOT (FROMNAME=AreaFix or FROMNAME=Raid)
Variables
---------
String variables
FROMNAME
TONAME
SUBJECT
AREA
TYPE
SOURCE
FROMNAME, TONAME and SUBJECT should be self-explanatory. AREA is the tagname
of the area for echomail messages and for netmail messages it will be empty.
TYPE can be either NETMAIL or ECHOMAIL. SOURCE describes where the message
came from and can have these values:
TOSSED message was read from a *.pkt file
EXPORTED message was exported from a messagebase
CRASHMAIL message was generated by CrashMail (bounce messages, AreaFix
responses etc)
The "=" operator matches a variable against a pattern (see description of
CrashMail's patterns in ReadMe.txt). "|" makes a substring search.
Examples:
FROMNAME=Johan*
SOURCE=CRASHMAIL
SUBJECT|AreaFix
Node variables
FROMADDR
TOADDR
For netmail messages, these are the addresses found in the message header.
For echomail messages, FROMADDR is taken from the Origin line and TOADDR
will be empty.
Node variables are matched against a node pattern using the "=" operator.
Examples:
FROMADDR="1:*/*.*"
TOADDR="2:200/207.6"
Text variables
TEXT
KLUDGES
TEXT is the message text without kludges and KLUDGES contains all the kludges
(lines beginning with 0x01). You can only do substring searches on text
variables using the "|" operator.
Examples:
TEXT|CrashMail
KLUDGES|"TID: CrashMail"
Boolean variables
FILEATTACH
TOLOCALAKA
FROMLOCALAKA
TOLOCALPOINT
FROMLOCALPOINT
EXISTSCFG_FROMADDR
EXISTSCFG_FROMBOSS
EXISTSCFG_TOADDR
EXISTSCFG_TOBOSS
EXISTSNL_FROMADDR
EXISTSNL_FROMBOSS
EXISTSNL_TOADDR
EXISTSNL_TOBOSS
Boolean variables are always TRUE or FALSE. Boolean variables can be used
either alone (variable and variable=TRUE is the same thing) or as
variable=TRUE/FALSE.
FILEATTACH will be TRUE if the message has an attached file.
FROMLOCALAKA/TOLOCALAKA will be TRUE if the message is from/to one of the
AKAs configured in the configuration file. FROMLOCALPOINT/TOLOCALPOINT will
be TRUE if the message is from/to a point under one of the AKAs configured
in the configuration file.
EXISTSCFG_FROMADDR will be TRUE if the message is from an address configured
as a NODE in the configuration file. EXISTSCFG_FROMBOSS is similar, but if
the node is a point (x:y/z.p), CrashMail will look for the boss (x:y/z.0) in
the node configuration instead. EXISTSCFG_TOADDR/EXISTSCFG_TOBOSS are similar,
but for the destination address.
EXISTSNL_* are similar to EXISTSCFG_*, but instead of looking for the nodes
in the node configuration, the variable will only the TRUE if the node is
found in the external nodelist.
Examples:
TOLOCALAKA or TOLOCALAKA=TRUE (equivalent)
FROMLOCALPOINT=FALSE or NOT FROMLOCALPOINT (equivalent)
Commands
--------
TWIT
Don't import the message. The message will be sent to downlinks as usual.
Example:
FILTER TYPE=ECHOMAIL and FROMNAME="Hubba Hopp"
TWIT
KILL
Completely discard the message.
Example:
FILTER SOURCE=CRASHMAIL
KILL
COPY <area>
Write a copy of the message to a local area. The local area needs to be
configured in the configuration using LOCALAREA.
Example:
FILTER SOURCE=TOSSED and TYPE=ECHOMAIL and TONAME="Johan Billing"
COPY PERSONAL_MESSAGES
EXECUTE <command>
Executes an external command. The following codes can be used in the command:
%r RFC-style with Fidonet addresses. Name of a file that contains a
message in a text format similar to that used for e-mail messages on
the internet, but addresses are still in x:x/x.x@domain format.
%R RFC-style with RFC-style addresses. Name of a file that contains a
message in a text format similar to that used for e-mail messages on
the internet, but addresses are in name@pX.fX.nX.zX.domain format.
%m Name of a file that contains the message as a *.msg file
%a Area name (echomail only, will be empty for netmail areas)
%f From name
%o Originating node
%t To name
%d Destination node
%s Subject
%x Date and time of the message
CrashMail will react differently depending on the exit code of the executed
command:
0 The message is not imported
10 The message is imported
20 CrashMail aborts
Example:
FILTER TYPE=NETMAIL and TOLOCALAKA and TONAME="Raid"
EXECUTE "raid %r"
WRITELOG <message>
Writes a message to the logfile (loglevel 1). The same %-codes as for the
EXECUTE command can be used here as well except for %r, %R and %m.
Example:
FILTER TYPE=ECHOMAIL and SOURCE=TOSSED
WRITELOG "From: %f Subj: %s Area: %a"
WRITEBAD <reason>
Writes the message to the BAD area with <reason> specified as the reason. The
message is not deleted unless you also use the KILL command.
FILTER TYPE=NETMAIL and NOT EXISTSNL_TOBOSS
WRITEBAD "Warning: Destination not in nodelist, message might not arrive"
BOUNCEMSG <message>
BOUNCEHEADER <message>
These commands writes an error message to the sender of the filtered message.
BOUNCEMSG includes a full copy of the original message and BOUNCEHEADER only
includes the message header. In the message to the sender, you can use the
same %-codes as for the EXECUTE command except for %r, %R and %m. The message
will not be deleted unless you also use the KILL command.
Example:
FILTER TYPE=NETMAIL and not TOLOCALAKA and not EXISTSCFG_TOADDR
BOUNCEMSG "Destination node %d does not exist, message can not be delivered"
KILL
REMAPMSG <new name> <destination pattern>
This command can change the destination name and node of a netmail message. If
the new name is "*", the old name will be kept.
Examples:
FILTER TYPE=NETMAIL and TOLOCALAKA and TONAME="Johannes"
REMAPMSG "Johannes Nilsson" 2:200/2075
FILTER TYPE=NETMAIL and TOADDR=2:999/*.*
REMAPMSG "*" 2:200/*.*
Additional examples
-------------------
Copy all talk about me to a special area:
FILTER TYPE=ECHOMAIL and SOURCE=TOSSED and TEXT|billing
COPY BILLING_DISCUSSIONS
Keep a copy of all sent netmails:
FILTER TYPE=NETMAIL and SOURCE=EXPORTED
COPY SENT_NETMAILS
Log all routed messages:
FILTER TYPE=NETMAIL and SOURCE=TOSSED
WRITELOG "Routed message from %f (%o) to %t (%d)"
Search all messages for a string:
FILTER TEXT|CrashMail
COPY CRASHMAIL_DISCUSSIONS
Make customized bounce messages:
FILTER TYPE=NETMAIL AND NOT EXISTSNL_TOBOSS
BOUNCEMSG "Destination node %d does not exist in nodelist, your message cannot be delivered"
KILL
Make it possible to inspect all messages generated by CrashMail:
FILTER SOURCE=CRASHMAIL
COPY CRASHMAIL_MESSAGES

View File

@ -0,0 +1,29 @@
# type either "make linux" or "make win32" to compile
help:
@echo You can use this Makefile in the following ways:
@echo make linux ............ Make Linux binaries
@echo make cleanlinux ....... Remove object files under Linux
freebsd:
mkdir -p obj
gmake -C cmnllib -f Makefile.linux
gmake -C oslib_linux
gmake -f Makefile.linux
linux :
mkdir -p obj
make -C cmnllib -f Makefile.linux
make -C oslib_linux
make -f Makefile.linux
cleanfreebsd :
gmake -C cmnllib -f Makefile.linux clean
gmake -C oslib_linux clean
gmake -f Makefile.linux clean
cleanlinux :
make -C cmnllib -f Makefile.linux clean
make -C oslib_linux clean
make -f Makefile.linux clean

View File

@ -0,0 +1,219 @@
# Makefile for Linux
# General
PLATFORMDEF = -DPLATFORM_LINUX
EXESUFFIX =
BINDIR = ../bin
OBJDIR = obj
INCDIR = ./
OSLIB = oslib_linux/oslib.a
JAMLIB = ../../../deps/jamlib/jamlib.a
CMNLLIB = cmnllib/cmnllib.a
# Nodelists
NLDEFS = -DNODELIST_CMNL -DNODELIST_V7P
NLOBJS = obj/nl_v7p.o obj/nl_cmnl.o $(CMNLLIB)
# Messagebases
# *.msg
MBDEFS_MSG = -DMSGBASE_MSG
MBOBJS_MSG = obj/mb_msg.o
# JAM
MBDEFS_JAM = -DMSGBASE_JAM
MBOBJS_JAM = $(OBJDIR)/mb_jam.o $(JAMLIB)
MBDEFS_SQ3 = -DMSGBASE_SQ3
MBOBJS_SQ3 = $(OBJDIR)/mb_sq3.o
# Sum them up. Only include the messagebases you want to use
MBDEFS = $(MBDEFS_MSG) $(MBDEFS_JAM) $(MBDEFS_SQ3)
MBOBJS = $(MBOBJS_MSG) $(MBOBJS_JAM) $(MBOBJS_SQ3)
DEFS = $(PLATFORMDEF) $(MBDEFS) $(NLDEFS)
# Commands
CC = gcc $(CPPFLAGS) $(CFLAGS) $(DEFS) $(LDFLAGS) -I $(INCDIR) -I ../../../deps/ -Wall
RM = rm -f
STRIP = strip
# Objects
SHOBJS = $(OBJDIR)/jblist.o \
$(OBJDIR)/jbstrcpy.o \
$(OBJDIR)/mystrncpy.o \
$(OBJDIR)/parseargs.o \
$(OBJDIR)/node4d.o \
$(OBJDIR)/expr.o \
$(OBJDIR)/path.o
CMOBJS = $(OBJDIR)/magimail.o \
$(OBJDIR)/logwrite.o \
$(OBJDIR)/dupe.o \
$(OBJDIR)/stats.o \
$(OBJDIR)/misc.o \
$(OBJDIR)/safedel.o \
$(OBJDIR)/toss.o \
$(OBJDIR)/pkt.o \
$(OBJDIR)/mb.o \
$(OBJDIR)/nl.o \
$(OBJDIR)/handle.o \
$(OBJDIR)/node4dpat.o \
$(OBJDIR)/config.o \
$(OBJDIR)/memmessage.o \
$(OBJDIR)/scan.o \
$(OBJDIR)/outbound.o \
$(OBJDIR)/filter.o \
$(OBJDIR)/areafix.o
files : $(BINDIR)/magimail$(EXESUFFIX) \
$(BINDIR)/magistats$(EXESUFFIX) \
$(BINDIR)/magilist$(EXESUFFIX) \
$(BINDIR)/magigetnode$(EXESUFFIX) \
$(BINDIR)/magimaint$(EXESUFFIX) \
$(BINDIR)/magiwrite$(EXESUFFIX) \
$(BINDIR)/magiexport$(EXESUFFIX) \
$(BINDIR)/magilistout$(EXESUFFIX)
$(BINDIR)/magimail$(EXESUFFIX) : $(CMOBJS) $(SHOBJS) $(NLOBJS) $(MBOBJS) $(OSLIB)
$(CC) -o $(BINDIR)/magimail$(EXESUFFIX) $(CMOBJS) $(SHOBJS) $(NLOBJS) $(MBOBJS) $(OSLIB) -lsqlite3
$(STRIP) $(BINDIR)/magimail$(EXESUFFIX)
$(BINDIR)/magistats$(EXESUFFIX) : tools/magistats.c $(SHOBJS) $(OSLIB)
$(CC) -o $(BINDIR)/magistats$(EXESUFFIX) tools/magistats.c $(SHOBJS) $(OSLIB)
$(STRIP) $(BINDIR)/magistats$(EXESUFFIX)
$(BINDIR)/magilist$(EXESUFFIX) : tools/magilist.c $(SHOBJS) $(OSLIB)
$(CC) -o $(BINDIR)/magilist$(EXESUFFIX) tools/magilist.c $(SHOBJS) $(OSLIB)
$(STRIP) $(BINDIR)/magilist$(EXESUFFIX)
$(BINDIR)/magigetnode$(EXESUFFIX) : tools/magigetnode.c $(SHOBJS) $(CMNLLIB) $(OSLIB)
$(CC) -o $(BINDIR)/magigetnode$(EXESUFFIX) tools/magigetnode.c $(SHOBJS) $(CMNLLIB) $(OSLIB)
$(STRIP) $(BINDIR)/magigetnode$(EXESUFFIX)
$(BINDIR)/magimaint$(EXESUFFIX) : tools/magimaint.c $(SHOBJS) $(OSLIB) $(JAMLIB)
$(CC) -o $(BINDIR)/magimaint$(EXESUFFIX) tools/magimaint.c $(SHOBJS) $(OSLIB) $(JAMLIB)
$(STRIP) $(BINDIR)/magimaint$(EXESUFFIX)
$(BINDIR)/magiwrite$(EXESUFFIX) : tools/magiwrite.c $(SHOBJS) $(OSLIB)
$(CC) -o $(BINDIR)/magiwrite$(EXESUFFIX) tools/magiwrite.c $(SHOBJS) $(OSLIB)
$(STRIP) $(BINDIR)/magiwrite$(EXESUFFIX)
$(BINDIR)/magiexport$(EXESUFFIX) : tools/magiexport.c $(SHOBJS) $(OSLIB)
$(CC) -o $(BINDIR)/magiexport$(EXESUFFIX) tools/magiexport.c $(SHOBJS) $(OSLIB)
$(STRIP) $(BINDIR)/magiexport$(EXESUFFIX)
$(BINDIR)/magilistout$(EXESUFFIX) : tools/magilistout.c $(SHOBJS) $(OSLIB)
$(CC) -o $(BINDIR)/magilistout$(EXESUFFIX) tools/magilistout.c $(SHOBJS) $(OSLIB)
$(STRIP) $(BINDIR)/magilistout$(EXESUFFIX)
# magimail
$(OBJDIR)/magimail.o : magimail/magimail.c
$(CC) -c magimail/magimail.c -o $(OBJDIR)/magimail.o
$(OBJDIR)/logwrite.o : magimail/logwrite.c
$(CC) -c magimail/logwrite.c -o $(OBJDIR)/logwrite.o
$(OBJDIR)/dupe.o : magimail/dupe.c
$(CC) -c magimail/dupe.c -o $(OBJDIR)/dupe.o
$(OBJDIR)/stats.o : magimail/stats.c
$(CC) -c magimail/stats.c -o $(OBJDIR)/stats.o
$(OBJDIR)/misc.o : magimail/misc.c
$(CC) -c magimail/misc.c -o $(OBJDIR)/misc.o
$(OBJDIR)/safedel.o : magimail/safedel.c
$(CC) -c magimail/safedel.c -o $(OBJDIR)/safedel.o
$(OBJDIR)/toss.o : magimail/toss.c
$(CC) -c magimail/toss.c -o $(OBJDIR)/toss.o
$(OBJDIR)/scan.o : magimail/scan.c
$(CC) -c magimail/scan.c -o $(OBJDIR)/scan.o
$(OBJDIR)/pkt.o : magimail/pkt.c
$(CC) -c magimail/pkt.c -o $(OBJDIR)/pkt.o
$(OBJDIR)/memmessage.o : magimail/memmessage.c
$(CC) -c magimail/memmessage.c -o $(OBJDIR)/memmessage.o
$(OBJDIR)/handle.o : magimail/handle.c
$(CC) -c magimail/handle.c -o $(OBJDIR)/handle.o
$(OBJDIR)/node4dpat.o : magimail/node4dpat.c
$(CC) -c magimail/node4dpat.c -o $(OBJDIR)/node4dpat.o
$(OBJDIR)/config.o : magimail/config.c
$(CC) -c magimail/config.c -o $(OBJDIR)/config.o
$(OBJDIR)/outbound.o : magimail/outbound.c
$(CC) -c magimail/outbound.c -o $(OBJDIR)/outbound.o
$(OBJDIR)/areafix.o : magimail/areafix.c
$(CC) -c magimail/areafix.c -o $(OBJDIR)/areafix.o
$(OBJDIR)/filter.o : magimail/filter.c
$(CC) -c magimail/filter.c -o $(OBJDIR)/filter.o
# shared
$(OBJDIR)/jblist.o : shared/jblist.c
$(CC) -c shared/jblist.c -o $(OBJDIR)/jblist.o
$(OBJDIR)/jbstrcpy.o : shared/jbstrcpy.c
$(CC) -c shared/jbstrcpy.c -o $(OBJDIR)/jbstrcpy.o
$(OBJDIR)/mystrncpy.o : shared/mystrncpy.c
$(CC) -c shared/mystrncpy.c -o $(OBJDIR)/mystrncpy.o
$(OBJDIR)/parseargs.o : shared/parseargs.c
$(CC) -c shared/parseargs.c -o $(OBJDIR)/parseargs.o
$(OBJDIR)/path.o : shared/path.c
$(CC) -c shared/path.c -o $(OBJDIR)/path.o
$(OBJDIR)/node4d.o : shared/node4d.c
$(CC) -c shared/node4d.c -o $(OBJDIR)/node4d.o
$(OBJDIR)/expr.o : shared/expr.c
$(CC) -c shared/expr.c -o $(OBJDIR)/expr.o
# mb
$(OBJDIR)/mb.o : magimail/mb.c
$(CC) -c magimail/mb.c -o $(OBJDIR)/mb.o
$(OBJDIR)/mb_msg.o : magimail/mb_msg.c
$(CC) -c magimail/mb_msg.c -o $(OBJDIR)/mb_msg.o
$(OBJDIR)/mb_jam.o : magimail/mb_jam.c
$(CC) -c magimail/mb_jam.c -o $(OBJDIR)/mb_jam.o
$(OBJDIR)/mb_sq3.o : magimail/mb_sq3.c
$(CC) -c magimail/mb_sq3.c -o $(OBJDIR)/mb_sq3.o
# nl
$(OBJDIR)/nl.o : magimail/nl.c
$(CC) -c magimail/nl.c -o $(OBJDIR)/nl.o
$(OBJDIR)/nl_cmnl.o : magimail/nl_cmnl.c
$(CC) -c magimail/nl_cmnl.c -o $(OBJDIR)/nl_cmnl.o
$(OBJDIR)/nl_v7p.o : magimail/nl_v7p.c
$(CC) -c magimail/nl_v7p.c -o $(OBJDIR)/nl_v7p.o
# Clean
clean :
$(RM) $(OBJDIR)/*.o

View File

@ -0,0 +1,17 @@
INCDIR = ../
CC = gcc $(CPPFLAGS) $(CFLAGS) -DPLATFORM_LINUX $(LDFLAGS) -I $(INCDIR) -Wall
AR = ar -ru
RM = rm -f
OBJS = cmnllib.o
cmnllib.a : $(OBJS)
$(AR) cmnllib.a $(OBJS)
cmnllib.o: cmnllib.c
$(CC) -c cmnllib.c -o cmnllib.o
clean :
$(RM) *.o *.a

View File

@ -0,0 +1,149 @@
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <oslib/os.h>
#include <oslib/osfile.h>
#include <shared/types.h>
#include <shared/path.h>
#include "cmnllib.h"
struct idx
{
uint16_t zone,net,node,point,region,hub;
uint32_t offset;
};
uint32_t cmnlerr;
char *cmnlerrstr[] =
{
"",
"Failed to open nodelist index",
"Unknown format of nodelist index",
"Unexpected end of file",
"Node not found",
"Failed to open nodelist"
};
uint16_t cmnlgetuword(uint8_t *buf,uint32_t offset)
{
return (uint16_t)(buf[offset]+256*buf[offset+1]);
}
uint32_t cmnlgetlong(uint8_t *buf,uint32_t offset)
{
return (long) buf[offset]+
buf[offset+1]*256+
buf[offset+2]*256*256+
buf[offset+3]*256*256*256;
}
osFile cmnlOpenNL(char *dir)
{
osFile fh;
char buf[200];
MakeFullPath(dir,"cmnodelist.index",buf,200);
if(!(fh=osOpen(buf,MODE_OLDFILE)))
{
cmnlerr=CMNLERR_NO_INDEX;
return(NULL);
}
osRead(fh,buf,4);
buf[4]=0;
if(strcmp(buf,"CNL1")!=0)
{
osClose(fh);
cmnlerr=CMNLERR_WRONG_TYPE;
return(NULL);
}
return(fh);
}
void cmnlCloseNL(osFile nl)
{
osClose(nl);
}
bool cmnlFindNL(osFile nl,char *dir,struct cmnlIdx *cmnlidx,char *line,uint32_t len)
{
char buf[200];
char nlname[100];
struct idx idx;
bool found;
osFile fh;
uint8_t binbuf[16];
osSeek(nl,4,OFFSET_BEGINNING);
found=FALSE;
while(!found)
{
if(osRead(nl,nlname,100)!=100)
{
cmnlerr=CMNLERR_NODE_NOT_FOUND;
return(FALSE);
}
idx.offset=0;
while(!found && idx.offset != 0xffffffff)
{
if(osRead(nl,binbuf,sizeof(binbuf)) != sizeof(binbuf))
{
cmnlerr=CMNLERR_UNEXPECTED_EOF;
return(FALSE);
}
idx.zone=cmnlgetuword(binbuf,0);
idx.net=cmnlgetuword(binbuf,2);
idx.node=cmnlgetuword(binbuf,4);
idx.point=cmnlgetuword(binbuf,6);
idx.region=cmnlgetuword(binbuf,8);
idx.hub=cmnlgetuword(binbuf,10);
idx.offset=cmnlgetlong(binbuf,12);
found=TRUE;
if(cmnlidx->zone != idx.zone) found=FALSE;
if(cmnlidx->net != idx.net) found=FALSE;
if(cmnlidx->node != idx.node) found=FALSE;
if(cmnlidx->point != idx.point) found=FALSE;
}
}
cmnlidx->region=idx.region;
cmnlidx->hub=idx.hub;
if(!line)
{
return(TRUE);
}
MakeFullPath(dir,nlname,buf,200);
if(!(fh=osOpen(buf,MODE_OLDFILE)))
{
cmnlerr=CMNLERR_NO_NODELIST;
return(FALSE);
}
osSeek(fh,idx.offset,OFFSET_BEGINNING);
osFGets(fh,line,len);
osClose(fh);
return(TRUE);
}
char *cmnlLastError(void)
{
return cmnlerrstr[cmnlerr];
}

View File

@ -0,0 +1,19 @@
#include "shared/types.h"
struct cmnlIdx
{
uint16_t zone,net,node,point,region,hub;
};
#define CMNLERR_NO_INDEX 1
#define CMNLERR_WRONG_TYPE 2
#define CMNLERR_UNEXPECTED_EOF 3
#define CMNLERR_NODE_NOT_FOUND 4
#define CMNLERR_NO_NODELIST 5
osFile cmnlOpenNL(char *dir);
void cmnlCloseNL(osFile nl);
bool cmnlFindNL(osFile nl,char *dir,struct cmnlIdx *idx,char *line,uint32_t len);
char *cmnlLastError(void);
extern uint32_t cmnlerr;

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,14 @@
#define SENDLIST_FULL 1
#define SENDLIST_QUERY 2
#define SENDLIST_UNLINKED 3
#define SENDLIST_HELP 4
#define SENDLIST_INFO 5
void DoSendAFList(short type,struct ConfigNode *cnode);
bool AreaFix(struct MemMessage *mm);
void SendRemoveMessages(struct Area *area);
void RemoveDeletedAreas(void);

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,377 @@
#ifndef CONFIG_H
#define CONFIG_H
#define READCONFIG_NOT_FOUND 1
#define READCONFIG_INVALID 2
#define READCONFIG_NO_MEM 3
#define CFG_CHECKSEENBY (1L<<0)
#define CFG_CHECKPKTDEST (1L<<1)
#define CFG_STRIPRE (1L<<2)
#define CFG_FORCEINTL (1L<<3)
#define CFG_NOROUTE (1L<<4)
#define CFG_PATH3D (1L<<5)
#define CFG_IMPORTSEENBY (1L<<6)
#define CFG_IMPORTEMPTYNETMAIL (1L<<7)
#define CFG_BOUNCEPOINTS (1L<<8)
#define CFG_ANSWERRECEIPT (1L<<9)
#define CFG_ANSWERAUDIT (1L<<10)
#define CFG_NODIRECTATTACH (1L<<11)
#define CFG_IMPORTAREAFIX (1L<<12)
#define CFG_AREAFIXREMOVE (1L<<13)
#define CFG_WEEKDAYNAMING (1L<<14)
#define CFG_ADDTID (1L<<16)
#define CFG_ALLOWRESCAN (1L<<18)
#define CFG_FORWARDPASSTHRU (1L<<19)
#define CFG_BOUNCEHEADERONLY (1L<<21)
#define CFG_REMOVEWHENFEED (1L<<22)
#define CFG_INCLUDEFORWARD (1L<<23)
#define CFG_NOMAXOUTBOUNDZONE (1L<<24)
#define CFG_ALLOWKILLSENT (1L<<25)
#define CFG_FLOWCRLF (1L<<26)
#define CFG_NOEXPORTNETMAIL (1L<<27)
#ifdef MSGBASE_MSG
#define CFG_MSG_HIGHWATER (1L<<1)
#define CFG_MSG_WRITEBACK (1L<<2)
#endif
#ifdef MSGBASE_UMS
#define CFG_UMS_MAUSGATE (1L<<0)
#define CFG_UMS_KEEPORIGIN (1L<<1)
#define CFG_UMS_CHANGEMSGID (1L<<2)
#define CFG_UMS_IGNOREORIGINDOMAIN (1L<<3)
#define CFG_UMS_EMPTYTOALL (1L<<4)
#endif
#ifdef MSGBASE_JAM
#define CFG_JAM_HIGHWATER (1L<<0)
#define CFG_JAM_LINK (1L<<1)
#define CFG_JAM_QUICKLINK (1L<<2)
#endif
#ifdef PLATFORM_AMIGA
#define CFG_AMIGA_UNATTENDED (1L<<0)
#endif
#define AREA_UNCONFIRMED 1
#define AREA_MANDATORY 2
#define AREA_DEFREADONLY 4
#define AREA_IGNOREDUPES 8
#define AREA_IGNORESEENBY 16
#define AREATYPE_NETMAIL 1
#define AREATYPE_ECHOMAIL 2
#define AREATYPE_DEFAULT 3
#define AREATYPE_BAD 4
#define AREATYPE_LOCAL 5
#define AREATYPE_DELETED 6
struct Area
{
struct Area *Next;
bool changed;
struct Aka *Aka;
char Flags;
char AreaType;
char Tagname[80];
char Description[80];
struct Messagebase *Messagebase;
char Path[80];
char Group;
struct jbList TossNodes;
struct jbList BannedNodes;
/* Maint */
uint32_t KeepNum,KeepDays;
/* Stats */
uint32_t Texts;
uint32_t NewTexts;
uint32_t Dupes;
uint32_t NewDupes;
uint16_t Last8Days[8];
time_t FirstTime;
time_t LastTime;
/* Other */
bool scanned;
};
struct Aka
{
struct Aka *Next;
struct Node4D Node;
char Domain[20];
struct jbList AddList;
struct jbList RemList;
};
#define TOSSNODE_READONLY 1
#define TOSSNODE_WRITEONLY 2
#define TOSSNODE_FEED 4
struct TossNode
{
struct TossNode *Next;
struct ConfigNode *ConfigNode;
uint16_t Flags;
};
struct ImportNode
{
struct ImportNode *Next;
struct Node4D Node;
};
struct BannedNode
{
struct BannedNode *Next;
struct ConfigNode *ConfigNode;
};
#define NODE_AUTOADD 1
#define NODE_PASSIVE 2
#define NODE_TINYSEENBY 4
#define NODE_NOSEENBY 8
#define NODE_FORWARDREQ 16
#define NODE_NOTIFY 32
#define NODE_PACKNETMAIL 64
#define NODE_SENDAREAFIX 128
#define NODE_SENDTEXT 256
#define NODE_PKTFROM 512
#define NODE_AFNEEDSPLUS 1024
struct RemoteAFCommand
{
struct RemoteAFCommand *Next;
char Command[80];
};
struct ConfigNode
{
struct ConfigNode *Next;
bool changed;
struct Node4D Node;
char PacketPW[9];
struct Packer *Packer;
bool IsInSeenBy;
char AreafixPW[40];
char Groups[30];
char ReadOnlyGroups[30];
char AddGroups[30];
char DefaultGroup;
uint32_t Flags;
char SysopName[36];
char EchomailPri;
struct Node4D PktFrom;
char RemoteAFName[36];
char RemoteAFPw[72];
struct jbList RemoteAFList;
char LastArcName[12];
/* Stats */
uint32_t GotNetmails;
uint32_t GotNetmailBytes;
uint32_t SentNetmails;
uint32_t SentNetmailBytes;
uint32_t GotEchomails;
uint32_t GotEchomailBytes;
uint32_t SentEchomails;
uint32_t SentEchomailBytes;
uint32_t Dupes;
time_t FirstTime;
};
struct Packer
{
struct Packer *Next;
char Name[10];
char Packer[80];
char Unpacker[80];
char Recog[80];
};
struct AddNode
{
struct AddNode *Next;
struct Node4D Node;
};
struct RemNode
{
struct RemNode *Next;
struct Node2DPat NodePat;
};
struct Route
{
struct Route *Next;
struct Node4DPat Pattern;
struct Node4DPat DestPat;
struct Aka *Aka;
};
struct PatternNode
{
struct PatternNode *Next;
struct Node4DPat Pattern;
};
#define PKTS_ECHOMAIL 0
#define PKTS_HOLD 1
#define PKTS_NORMAL 2
#define PKTS_DIRECT 3
#define PKTS_CRASH 4
struct Change
{
struct Change *Next;
struct Node4DPat Pattern;
bool ChangeNormal;
bool ChangeCrash;
bool ChangeDirect;
bool ChangeHold;
char DestPri;
};
struct AreaFixName
{
struct AreaFixName *Next;
char Name[36];
};
#define AREALIST_DESC 1
#define AREALIST_FORWARD 2
struct Arealist
{
struct Arealist *Next;
struct ConfigNode *Node;
char AreaFile[80];
uint16_t Flags;
char Group;
};
#define COMMAND_KILL 1
#define COMMAND_TWIT 2
#define COMMAND_COPY 3
#define COMMAND_EXECUTE 4
#define COMMAND_WRITELOG 5
#define COMMAND_WRITEBAD 6
#define COMMAND_BOUNCEMSG 7
#define COMMAND_BOUNCEHEADER 8
#define COMMAND_REMAPMSG 9
struct Command
{
struct Command *Next;
uint16_t Cmd;
char *string;
struct Node4D n4d;
struct Node4DPat n4ddestpat;
};
struct Filter
{
struct Filter *Next;
char Filter[400];
struct jbList CommandList;
};
#define DUPE_IGNORE 0
#define DUPE_BAD 1
#define DUPE_KILL 2
#define LOOP_IGNORE 0
#define LOOP_LOG 1
#define LOOP_LOGBAD 2
struct Config
{
bool changed;
char filename[100];
char cfg_Sysop[36];
char cfg_Inbound[100];
char cfg_Outbound[100];
char cfg_TempDir[100];
char cfg_PacketCreate[100];
char cfg_PacketDir[100];
char cfg_LogFile[100];
char cfg_StatsFile[100];
char cfg_DupeFile[100];
char cfg_BeforeToss[80];
char cfg_BeforePack[80];
uint32_t cfg_LogLevel;
uint32_t cfg_DupeSize;
uint32_t cfg_MaxPktSize;
uint32_t cfg_MaxBundleSize;
char cfg_AreaFixHelp[100];
char cfg_Nodelist[100];
struct Nodelist *cfg_NodelistType;
uint32_t cfg_AreaFixMaxLines;
char cfg_GroupNames[30][80];
uint32_t cfg_Flags;
uint16_t cfg_DupeMode;
uint16_t cfg_LoopMode;
uint32_t cfg_DefaultZone;
struct jbList AkaList;
struct jbList AreaList;
struct jbList CNodeList;
struct jbList PackerList;
struct jbList RouteList;
struct jbList FileAttachList;
struct jbList BounceList;
struct jbList ChangeList;
struct jbList AreaFixList;
struct jbList ArealistList;
struct jbList FilterList;
#ifdef PLATFORM_AMIGA
uint32_t cfg_amiga_LogBufferLines;
uint32_t cfg_amiga_LogBufferSecs;
uint32_t cfg_amiga_Flags;
#endif
#ifdef MSGBASE_UMS
char cfg_ums_RFCGatewayName[40];
struct Node4D cfg_ums_RFCGatewayNode;
char cfg_ums_LoginName[80];
char cfg_ums_LoginPassword[80];
char cfg_ums_LoginServer[80];
char cfg_ums_GatewayName[36];
uint32_t cfg_ums_Flags;
#endif
#ifdef MSGBASE_MSG
uint32_t cfg_msg_Flags;
#endif
#ifdef MSGBASE_JAM
uint32_t cfg_jam_MaxOpen;
uint32_t cfg_jam_Flags;
#endif
};
bool ReadConfig(char *filename,struct Config *cfg,short *seconderr,uint32_t *cfgline,char *cfgerr);
bool UpdateConfig(struct Config *cfg,char *cfgerr);
void InitConfig(struct Config *cfg);
void FreeConfig(struct Config *cfg);
bool CheckConfig(struct Config *cfg,char *cfgerr);
/* Should not be called in prefs */
#endif

View File

@ -0,0 +1,314 @@
#include "magimail.h"
#define DUPES_IDENTIFIER "CDU2"
unsigned long cm_crc32tab[] = { /* CRC polynomial 0xedb88320 */
0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3,
0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91,
0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5,
0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f,
0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d,
0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457,
0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb,
0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9,
0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad,
0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683,
0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7,
0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79,
0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f,
0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21,
0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45,
0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db,
0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf,
0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
};
uint32_t calcstringcrc(char *str)
{
uint32_t crc;
int c;
crc=0xffffffff;
for(c=0;str[c];c++)
crc=(crc>>8) ^ cm_crc32tab[(unsigned char)crc ^ str[c]];
return(crc);
}
struct dupeentry
{
uint32_t offset;
uint32_t crc32;
};
bool dupechanged;
struct dupeentry *dupebuf;
uint32_t dupeentrynum,dupeentrymax;
osFile dupefh;
void adddupeindex(uint32_t offset,uint32_t crc32)
{
dupebuf[dupeentrynum].offset=offset;
dupebuf[dupeentrynum].crc32=crc32;
dupeentrynum++;
if(dupeentrynum > dupeentrymax)
dupeentrymax=dupeentrynum;
if(dupeentrynum == config.cfg_DupeSize)
dupeentrynum=0;
}
void copydupe(uint16_t c,osFile oldfh,osFile newfh)
{
char buf[300];
uint16_t size;
osSeek(oldfh,dupebuf[c].offset,OFFSET_BEGINNING);
if(osRead(oldfh,&size,sizeof(uint16_t))!=sizeof(uint16_t))
return;
if(osRead(oldfh,buf,size) != size)
return;
if(!osWrite(newfh,&size,sizeof(uint16_t)))
{
uint32_t err=osError();
LogWrite(1,SYSTEMERR,"Failed to write to temporary dupe file");
LogWrite(1,SYSTEMERR,"Error: %s",osErrorMsg(err));
return;
}
if(!osWrite(newfh,buf,size))
{
uint32_t err=osError();
LogWrite(1,SYSTEMERR,"Failed to write to temporary dupe file");
LogWrite(1,SYSTEMERR,"Error: %s",osErrorMsg(err));
return;
}
}
bool OpenDupeDB(void)
{
char buf[300];
uint32_t offset,crc32,*crc32p;
uint16_t size,res;
if(!(dupebuf=osAlloc(config.cfg_DupeSize*sizeof(struct dupeentry))))
{
LogWrite(1,SYSTEMERR,"Not enough memory for dupe-check buffer\n");
return(FALSE);
}
dupeentrynum=0;
dupeentrymax=0;
dupechanged=FALSE;
if(!(dupefh=osOpen(config.cfg_DupeFile,MODE_READWRITE)))
{
uint32_t err=osError();
LogWrite(1,SYSTEMERR,"Failed to open dupe file %s in read/write mode",config.cfg_DupeFile);
LogWrite(1,SYSTEMERR,"Error: %s",osErrorMsg(err));
return(FALSE);
}
res=osRead(dupefh,buf,4);
buf[4]=0;
if(res == 0)
{
/* New file */
LogWrite(3,TOSSINGINFO,"Creating new dupe file %s",config.cfg_DupeFile);
strcpy(buf,DUPES_IDENTIFIER);
osWrite(dupefh,buf,4);
}
else if(res != 4 || strcmp(buf,DUPES_IDENTIFIER)!=0)
{
LogWrite(1,SYSTEMERR,"Invalid format of dupe file %s, exiting...",config.cfg_DupeFile);
osClose(dupefh);
return(FALSE);
}
offset=4;
while(osRead(dupefh,&size,sizeof(uint16_t))==sizeof(uint16_t))
{
if(size == 0 || size > 300) /* Unreasonably big */
{
LogWrite(1,SYSTEMERR,"Error in dupe file %s, exiting...",config.cfg_DupeFile);
osClose(dupefh);
return(FALSE);
}
if(osRead(dupefh,buf,(uint32_t)size) != size)
{
LogWrite(1,SYSTEMERR,"Error in dupe file %s, exiting...",config.cfg_DupeFile);
osClose(dupefh);
return(FALSE);
}
crc32p=(uint32_t *)buf;
crc32=*crc32p;
adddupeindex(offset,crc32);
offset += size+2;
}
dupechanged=FALSE;
return(TRUE);
}
void CloseDupeDB(void)
{
osFile newfh;
uint32_t c;
char duptemp[200];
if(!dupechanged)
{
osClose(dupefh);
return;
}
strcpy(duptemp,config.cfg_DupeFile);
strcat(duptemp,".tmp");
if(!(newfh=osOpen(duptemp,MODE_NEWFILE)))
{
uint32_t err=osError();
LogWrite(1,SYSTEMERR,"Failed to open temporary dupe file %s for writing",duptemp);
LogWrite(1,SYSTEMERR,"Error: %s",osErrorMsg(err));
osFree(dupebuf);
osClose(dupefh);
return;
}
osWrite(newfh,DUPES_IDENTIFIER,4);
for(c=dupeentrynum;c<dupeentrymax;c++)
copydupe(c,dupefh,newfh);
for(c=0;c<dupeentrynum;c++)
copydupe(c,dupefh,newfh);
osClose(dupefh);
osClose(newfh);
osFree(dupebuf);
dupechanged=FALSE;
osDelete(config.cfg_DupeFile);
osRename(duptemp,config.cfg_DupeFile);
return;
}
void AddDupeBuf(char *buf,uint16_t size)
{
uint32_t offset;
uint32_t crc32,*crc32p;
osSeek(dupefh,0,OFFSET_END);
offset=osFTell(dupefh);
crc32p=(uint32_t *)buf;
crc32=*crc32p;
if(!osWrite(dupefh,&size,sizeof(uint16_t)))
{
uint32_t err=osError();
LogWrite(1,SYSTEMERR,"Failed to write to dupe file");
LogWrite(1,SYSTEMERR,"Error: %s",osErrorMsg(err));
return;
}
if(!osWrite(dupefh,buf,size))
{
uint32_t err=osError();
LogWrite(1,SYSTEMERR,"Failed to write to dupe file");
LogWrite(1,SYSTEMERR,"Error: %s",osErrorMsg(err));
return;
}
adddupeindex(offset,crc32);
dupechanged=TRUE;
}
int dupecomp(char *d1,char *d2,uint32_t len)
{
uint32_t c;
for(c=0;c<len;c++)
if(d1[c]!=d2[c]) return(1);
return(0);
}
bool CheckDupe(struct MemMessage *mm)
{
uint32_t c,crc32,*crc32p;
uint16_t size,dsize;
char dbuf[300],buf[300];
if(mm->MSGID[0] == 0)
return(FALSE); /* No dupechecking for messages without MSGID */
crc32=calcstringcrc(mm->MSGID);
crc32p=(uint32_t *)dbuf;
*crc32p=crc32;
dsize=4;
strcpy(&dbuf[dsize],mm->MSGID);
dsize += strlen(mm->MSGID) + 1;
strcpy(&dbuf[dsize],mm->Area);
dsize += strlen(mm->Area) + 1;
for(c=0;c<dupeentrymax;c++)
if(dupebuf[c].crc32 == crc32)
{
/* CRC matches, check rest */
osSeek(dupefh,dupebuf[c].offset,OFFSET_BEGINNING);
if(osRead(dupefh,&size,sizeof(uint16_t))==sizeof(uint16_t))
if(size == dsize)
if(osRead(dupefh,buf,(uint32_t)size) == size)
if(dupecomp(buf,dbuf,dsize) == 0)
return(TRUE); /* Dupe */
}
AddDupeBuf(dbuf,dsize);
return(FALSE);
}

View File

@ -0,0 +1,9 @@
#include "shared/types.h"
bool OpenDupeDB(void);
void CloseDupeDB(void);
bool CheckDupe(struct MemMessage *mm);

View File

@ -0,0 +1,978 @@
#include "magimail.h"
/* Boyer-Moore search routines */
uint16_t bmstep[256];
void bminit(char *pat)
{
int i,len;
len=strlen(pat);
for(i=0;i<256;i++)
bmstep[i]=0;
for(i=0;i<len;i++)
bmstep[tolower(pat[i])]=len-i-1;
for(i=0;i<256;i++)
if(bmstep[i] == 0) bmstep[i]=len;
}
long bmfind(char *pat,char *text,long textlen,long start)
{
long i,j,end,len;
len=strlen(pat);
end=textlen-len;
i=start;
while(i<=end)
{
for(j=len-1;j>=0;j--)
if(tolower(text[i+j])!=tolower(pat[j])) break;
if(j == -1)
return(i);
i+=bmstep[tolower(text[i+j])];
}
return(-1);
}
struct MemMessage *filter_mm;
int filter_nllookup(struct Node4D *node)
{
if(!config.cfg_NodelistType)
return(-1);
if(!nodelistopen)
return(1);
return (*config.cfg_NodelistType->nlCheckNode)(node);
}
int filter_comparenode(char *var,struct Node4D *node,char *operator,char *data,int opn,int datan,int *errpos,char **errstr)
{
static char errbuf[100];
struct Node4DPat pat;
if(operator[0]==0)
{
sprintf(errbuf,"%s is not a boolean variable",var);
*errstr=errbuf;
*errpos=opn;
return(-1);
}
if(strcmp(operator,"=")!=0)
{
sprintf(errbuf,"%s is not a valid operator for %s",operator,var);
*errstr=errbuf;
*errpos=opn;
return(-1);
}
if(!(Parse4DPat(data,&pat)))
{
sprintf(errbuf,"Invalid node pattern \"%s\"",data);
*errstr=errbuf;
*errpos=datan;
return(-1);
}
if(!config.cfg_NodelistType && !Check4DPatNodelist(&pat))
{
sprintf(errbuf,"Nodelist needed for pattern \"%s\"",data);
*errstr=errbuf;
*errpos=datan;
return(-1);
}
if(Compare4DPat(&pat,node)==0)
return(1);
return(0);
}
int filter_comparestring(char *var,char *str,char *operator,char *data,int opn,int datan,int *errpos,char **errstr)
{
static char errbuf[100];
if(operator[0]==0)
{
sprintf(errbuf,"%s is not a boolean variable",var);
*errstr=errbuf;
*errpos=opn;
return(-1);
}
if(strcmp(operator,"|")==0)
{
bminit(data);
if(bmfind(data,str,strlen(str),0) != -1)
return(1);
return(0);
}
else if(strcmp(operator,"=")==0)
{
if(!(osCheckPattern(data)))
{
sprintf(errbuf,"Invalid pattern \"%s\"",data);
*errstr=errbuf;
*errpos=datan;
return(-1);
}
if(osMatchPattern(data,str))
return(1);
return(0);
}
else
{
sprintf(errbuf,"%s is not a valid operator for %s",operator,var);
*errstr=errbuf;
*errpos=opn;
return(-1);
}
}
int filter_comparebool(char *var,bool bl,char *operator,char *data,int opn,int datan,int *errpos,char **errstr)
{
static char errbuf[100];
if(operator[0]==0)
{
if(bl)
return(1);
return(0);
}
else if(strcmp(operator,"=")==0)
{
if(stricmp(data,"TRUE")==0)
{
if(bl)
return(1);
return(0);
}
else if(stricmp(data,"FALSE")==0)
{
if(bl)
return(0);
return(1);
}
else
{
sprintf(errbuf,"Boolean variable %s can only be TRUE or FALSE",var);
*errstr=errbuf;
*errpos=datan;
return(-1);
}
}
else
{
sprintf(errbuf,"%s is not a valid operator for %s",operator,var);
*errstr=errbuf;
*errpos=opn;
return(-1);
}
}
int filter_comparetext(char *var,struct MemMessage *mm,bool kludge,char *operator,char *data,int opn,int datan,int *errpos,char **errstr)
{
static char errbuf[100];
struct TextChunk *chunk;
long start,pos,c;
if(operator[0]==0)
{
sprintf(errbuf,"%s is not a boolean variable",var);
*errstr=errbuf;
*errpos=opn;
return(-1);
}
if(strcmp(operator,"|")!=0)
{
sprintf(errbuf,"%s is not a valid operator for %s",operator,var);
*errstr=errbuf;
*errpos=opn;
return(-1);
}
bminit(data);
for(chunk=(struct TextChunk *)mm->TextChunks.First;chunk;chunk=chunk->Next)
{
/* Search chunk */
start=0;
while((pos=bmfind(data,chunk->Data,chunk->Length,start)) != -1)
{
start=pos+1;
for(c=pos;c>0 && chunk->Data[c]!=1 && chunk->Data[c]!=13;c--);
if(chunk->Data[c]==1 && kludge) return(1);
if(chunk->Data[c]!=1 && !kludge) return(1);
}
}
return(0);
}
int filter_evalfunc(char *str,int *errpos,char **errstr)
{
char type[20],source[20];
static char errbuf[100];
struct Aka *aka;
struct ConfigNode *cnode;
bool fileattach,tolocalaka,fromlocalaka,tolocalpoint,fromlocalpoint;
bool existscfg_fromaddr,existscfg_fromboss,existscfg_toaddr,existscfg_toboss;
char var[100],operator[2],data[100];
int opn,datan,res;
int c,d;
struct Node4D from4d,fromboss,toboss;
/* Parse statement */
c=0;
d=0;
while(str[c]!=0 && (isalpha(str[c]) || str[c] == '_') && d<99)
var[d++]=str[c++];
var[d]=0;
opn=c;
if(str[c]!=0)
{
operator[0]=str[c++];
operator[1]=0;
}
else
{
operator[0]=0;
}
datan=c;
if(str[c]=='"')
c++;
mystrncpy(data,&str[c],100);
if(data[0]!=0)
{
if(data[strlen(data)-1]=='"')
data[strlen(data)-1]=0;
}
/* Set real fromaddr and fromboss, toboss */
if(filter_mm->Area[0] == 0) Copy4D(&from4d,&filter_mm->OrigNode);
else Copy4D(&from4d,&filter_mm->Origin4D);
Copy4D(&fromboss,&from4d);
fromboss.Point=0;
Copy4D(&toboss,&filter_mm->DestNode);
toboss.Point=0;
/* Make local variables */
tolocalaka=FALSE;
fromlocalaka=FALSE;
tolocalpoint=FALSE;
fromlocalpoint=FALSE;
existscfg_fromaddr=FALSE;
existscfg_fromboss=FALSE;
existscfg_toaddr=FALSE;
existscfg_toboss=FALSE;
fileattach=FALSE;
for(aka=(struct Aka *)config.AkaList.First;aka;aka=aka->Next)
{
if(Compare4D(&filter_mm->DestNode,&aka->Node)==0) tolocalaka=TRUE;
if(Compare4D(&from4d,&aka->Node)==0) fromlocalaka=TRUE;
if(filter_mm->DestNode.Point != 0)
if(Compare4D(&aka->Node,&toboss)==0 && aka->Node.Point==0) tolocalpoint=TRUE;
if(from4d.Point != 0)
if(Compare4D(&aka->Node,&fromboss)==0 && aka->Node.Point==0) fromlocalpoint=TRUE;
}
for(cnode=(struct ConfigNode *)config.CNodeList.First;cnode;cnode=cnode->Next)
{
if(Compare4D(&cnode->Node,&from4d)==0) existscfg_fromaddr=TRUE;
if(Compare4D(&cnode->Node,&fromboss)==0) existscfg_fromboss=TRUE;
if(Compare4D(&cnode->Node,&filter_mm->DestNode)==0) existscfg_toaddr=TRUE;
if(Compare4D(&cnode->Node,&toboss)==0) existscfg_toboss=TRUE;
}
if(filter_mm->Attr & FLAG_FILEATTACH)
fileattach=TRUE;
if(filter_mm->Area[0]==0)
strcpy(type,"NETMAIL");
else
strcpy(type,"ECHOMAIL");
strcpy(source,"OTHER");
if(filter_mm->Flags & MMFLAG_EXPORTED)
strcpy(source,"EXPORTED");
if(filter_mm->Flags & MMFLAG_AUTOGEN)
strcpy(source,"CRASHMAIL");
if(filter_mm->Flags & MMFLAG_TOSSED)
strcpy(source,"TOSSED");
/* Compare */
if(stricmp(var,"FROMADDR")==0)
return filter_comparenode("FROMADDR",&from4d,operator,data,opn,datan,errpos,errstr);
if(stricmp(var,"TOADDR")==0)
return filter_comparenode("TOADDR",&filter_mm->DestNode,operator,data,opn,datan,errpos,errstr);
if(stricmp(var,"FROMNAME")==0)
return filter_comparestring("FROMNAME",filter_mm->From,operator,data,opn,datan,errpos,errstr);
if(stricmp(var,"TONAME")==0)
return filter_comparestring("TONAME",filter_mm->To,operator,data,opn,datan,errpos,errstr);
if(stricmp(var,"SUBJECT")==0)
return filter_comparestring("SUBJECT",filter_mm->Subject,operator,data,opn,datan,errpos,errstr);
if(stricmp(var,"AREA")==0)
return filter_comparestring("AREA",filter_mm->Area,operator,data,opn,datan,errpos,errstr);
if(stricmp(var,"TYPE")==0)
return filter_comparestring("TYPE",type,operator,data,opn,datan,errpos,errstr);
if(stricmp(var,"SOURCE")==0)
return filter_comparestring("SOURCE",source,operator,data,opn,datan,errpos,errstr);
if(stricmp(var,"FILEATTACH")==0)
return filter_comparebool("FILEATTACH",fileattach,operator,data,opn,datan,errpos,errstr);
if(stricmp(var,"TOLOCALAKA")==0)
return filter_comparebool("TOLOCALAKA",tolocalaka,operator,data,opn,datan,errpos,errstr);
if(stricmp(var,"FROMLOCALAKA")==0)
return filter_comparebool("FROMLOCALAKA",fromlocalaka,operator,data,opn,datan,errpos,errstr);
if(stricmp(var,"TOLOCALPOINT")==0)
return filter_comparebool("TOLOCALPOINT",tolocalpoint,operator,data,opn,datan,errpos,errstr);
if(stricmp(var,"FROMLOCALPOINT")==0)
return filter_comparebool("FROMLOCALPOINT",fromlocalpoint,operator,data,opn,datan,errpos,errstr);
if(stricmp(var,"EXISTSCFG_FROMADDR")==0)
return filter_comparebool("EXISTSCFG_FROMADDR",existscfg_fromaddr,operator,data,opn,datan,errpos,errstr);
if(stricmp(var,"EXISTSCFG_FROMBOSS")==0)
return filter_comparebool("EXISTSCFG_FROMBOSS",existscfg_fromboss,operator,data,opn,datan,errpos,errstr);
if(stricmp(var,"EXISTSCFG_TOADDR")==0)
return filter_comparebool("EXISTSCFG_TOADDR",existscfg_toaddr,operator,data,opn,datan,errpos,errstr);
if(stricmp(var,"EXISTSCFG_TOBOSS")==0)
return filter_comparebool("EXISTSCFG_TOBOSS",existscfg_toboss,operator,data,opn,datan,errpos,errstr);
if(stricmp(var,"EXISTSNL_FROMADDR")==0)
{
res=filter_nllookup(&from4d);
if(res == -1)
{
sprintf(errbuf,"Nodelist required for variable %s",var);
*errstr=errbuf;
*errpos=0;
return(-1);
}
return res;
}
if(stricmp(var,"EXISTSNL_FROMBOSS")==0)
{
res=filter_nllookup(&fromboss);
if(res == -1)
{
sprintf(errbuf,"Nodelist required for variable %s",var);
*errstr=errbuf;
*errpos=0;
return(-1);
}
return res;
}
if(stricmp(var,"EXISTSNL_TOADDR")==0)
{
res=filter_nllookup(&filter_mm->DestNode);
if(res == -1)
{
sprintf(errbuf,"Nodelist required for variable %s",var);
*errstr=errbuf;
*errpos=0;
return(-1);
}
return res;
}
if(stricmp(var,"EXISTSNL_TOBOSS")==0)
{
res=filter_nllookup(&toboss);
if(res == -1)
{
sprintf(errbuf,"Nodelist required for variable %s",var);
*errstr=errbuf;
*errpos=0;
return(-1);
}
return res;
}
if(stricmp(var,"EXISTSCFG_FROMBOSS")==0)
return filter_comparebool("EXISTSCFG_FROMBOSS",existscfg_fromboss,operator,data,opn,datan,errpos,errstr);
if(stricmp(var,"EXISTSCFG_TOADDR")==0)
return filter_comparebool("EXISTSCFG_TOADDR",existscfg_toaddr,operator,data,opn,datan,errpos,errstr);
if(stricmp(var,"EXISTSCFG_TOBOSS")==0)
return filter_comparebool("EXISTSCFG_TOBOSS",existscfg_toboss,operator,data,opn,datan,errpos,errstr);
if(stricmp(var,"TEXT")==0)
return filter_comparetext("TEXT",filter_mm,FALSE,operator,data,opn,datan,errpos,errstr);
if(stricmp(var,"KLUDGES")==0)
return filter_comparetext("KLUDGES",filter_mm,TRUE,operator,data,opn,datan,errpos,errstr);
sprintf(errbuf,"Unknown variable %s",var);
*errstr=errbuf;
*errpos=0;
return(-1);
}
bool Filter_Kill(struct MemMessage *mm)
{
char buf[200];
if(mm->Area[0] == 0)
{
Print4D(&mm->OrigNode,buf);
LogWrite(4,TOSSINGINFO,"Filter: Killing netmail from \"%s\" at %s",
mm->From,
buf);
}
else
{
LogWrite(4,TOSSINGINFO,"Filter: Killing message from \"%s\" in %s",
mm->From,
mm->Area);
}
mm->Flags |= MMFLAG_KILL;
return(TRUE);
}
bool Filter_Twit(struct MemMessage *mm)
{
char buf[200];
if(mm->Area[0] == 0)
{
Print4D(&mm->OrigNode,buf);
LogWrite(4,TOSSINGINFO,"Filter: Twitting netmail from \"%s\" at %s",
mm->From,
buf);
}
else
{
LogWrite(4,TOSSINGINFO,"Filter: Twitting message from \"%s\" in %s",
mm->From,
mm->Area);
}
mm->Flags |= MMFLAG_TWIT;
return(TRUE);
}
bool Filter_Copy(struct MemMessage *mm,char *tagname)
{
struct Area *area;
struct TextChunk *tmp;
struct jbList oldlist;
char buf[200];
LogWrite(4,TOSSINGINFO,"Filter: Copying message to area %s",tagname);
for(area=(struct Area *)config.AreaList.First;area;area=area->Next)
if(stricmp(area->Tagname,tagname)==0) break;
if(!area)
return(TRUE); /* We have already checked this in CheckConfig(), the area should exist */
oldlist.First=mm->TextChunks.First;
oldlist.Last=mm->TextChunks.Last;
jbNewList(&mm->TextChunks);
if(mm->Area[0])
{
sprintf(buf,"AREA:%s\x0d",mm->Area);
mmAddBuf(&mm->TextChunks,buf,strlen(buf));
}
for(tmp=(struct TextChunk *)oldlist.First;tmp;tmp=tmp->Next)
mmAddBuf(&mm->TextChunks,tmp->Data,tmp->Length);
if(!((*area->Messagebase->importfunc)(mm,area)))
return(FALSE);
area->NewTexts++;
jbFreeList(&mm->TextChunks);
mm->TextChunks.First=oldlist.First;
mm->TextChunks.Last=oldlist.Last;
return(TRUE);
}
bool Filter_WriteBad(struct MemMessage *mm,char *reason)
{
LogWrite(4,TOSSINGINFO,"Filter: Writing message to BAD area (\"%s\")",reason);
return WriteBad(mm,reason);
}
bool Filter_WriteLog(struct MemMessage *mm,char *cmd)
{
char buf[400];
char origbuf[30],destbuf[30];
if(mm->Area[0] == 0)
Print4D(&mm->OrigNode,origbuf);
else
Print4D(&mm->Origin4D,origbuf);
Print4D(&mm->DestNode,destbuf);
ExpandFilter(cmd,buf,400,
"",
"",
"",
mm->Area,
mm->Subject,
mm->DateTime,
mm->From,
mm->To,
origbuf,
destbuf);
LogWrite(1,TOSSINGINFO,"%s",buf);
return(TRUE);
}
bool Filter_Execute(struct MemMessage *mm,char *cmd)
{
bool msg,rfc1,rfc2;
char msgbuf[L_tmpnam],rfcbuf1[L_tmpnam],rfcbuf2[L_tmpnam];
char origbuf[30],destbuf[30];
char buf[400];
int arcres;
msg=FALSE;
rfc1=FALSE;
rfc2=FALSE;
msgbuf[0]=0;
rfcbuf1[0]=0;
rfcbuf2[0]=0;
if(strstr(cmd,"%m")) msg=TRUE;
if(strstr(cmd,"%r")) rfc1=TRUE;
if(strstr(cmd,"%R")) rfc2=TRUE;
if(rfc1) tmpnam(rfcbuf1);
if(rfc2) tmpnam(rfcbuf2);
if(msg) tmpnam(msgbuf);
if(mm->Area[0] == 0)
Print4D(&mm->OrigNode,origbuf);
else
Print4D(&mm->Origin4D,origbuf);
Print4D(&mm->DestNode,destbuf);
ExpandFilter(cmd,buf,400,
rfcbuf1,
rfcbuf2,
msgbuf,
mm->Area,
mm->Subject,
mm->DateTime,
mm->From,
mm->To,
origbuf,
destbuf);
if(rfc1) WriteRFC(mm,rfcbuf1,FALSE);
if(rfc2) WriteRFC(mm,rfcbuf2,TRUE);
if(msg) WriteMSG(mm,msgbuf);
LogWrite(4,SYSTEMINFO,"Filter: Executing external command \"%s\"",buf);
arcres=osExecute(buf);
if(rfc1) osDelete(rfcbuf1);
if(rfc2) osDelete(rfcbuf2);
if(msg) osDelete(msgbuf);
if(arcres == 0)
{
/* Command ok */
LogWrite(1,SYSTEMERR,"Filter: External command returned without error, killing message\n");
mm->Flags |= MMFLAG_KILL;
return(TRUE);
}
if(arcres >= 20)
{
LogWrite(1,SYSTEMERR,"Filter: External command failed with error %u, exiting...",arcres);
return(FALSE);
}
return(TRUE);
}
bool Filter_Bounce(struct MemMessage *mm,char *reason,bool headeronly)
{
char reasonbuf[400];
char origbuf[30],destbuf[30];
if(mm->Area[0] == 0)
Print4D(&mm->OrigNode,origbuf);
else
Print4D(&mm->Origin4D,origbuf);
Print4D(&mm->DestNode,destbuf);
ExpandFilter(reason,reasonbuf,400,
"",
"",
"",
mm->Area,
mm->Subject,
mm->DateTime,
mm->From,
mm->To,
origbuf,
destbuf);
LogWrite(4,TOSSINGINFO,"Filter: Bouncing message (\"%s\")",reasonbuf);
return Bounce(mm,reasonbuf,headeronly);
}
bool Filter_Remap(struct MemMessage *mm,char *namepat,struct Node4DPat *destpat)
{
struct Route *tmproute;
struct jbList oldlist;
struct TextChunk *tmp;
char buf[100];
char oldto[36],newto[36];
struct Node4D olddest4d,newdest4d,my4d;
uint32_t c,d;
bool skip;
if(mm->Area[0])
{
LogWrite(1,SYSTEMERR,"Filter: Only netmails can be remapped");
return(TRUE);
}
strcpy(oldto,mm->To);
Copy4D(&olddest4d,&mm->DestNode);
ExpandNodePat(destpat,&mm->DestNode,&newdest4d);
if(strcmp(namepat,"*")==0) strcpy(newto,mm->To);
else strcpy(newto,namepat);
my4d.Zone=0;
my4d.Net=0;
my4d.Node=0;
my4d.Point=0;
for(tmproute=(struct Route *)config.RouteList.First;tmproute;tmproute=tmproute->Next)
if(Compare4DPat(&tmproute->Pattern,&newdest4d)==0) break;
if(tmproute)
Copy4D(&my4d,&tmproute->Aka->Node);
LogWrite(4,SYSTEMINFO,"Filter: Remapping message to %s at %u:%u/%u.%u",
newto,
newdest4d.Zone,
newdest4d.Net,
newdest4d.Node,
newdest4d.Point);
LogWrite(4,SYSTEMINFO,"Filter: Message originally to %s at %u:%u/%u.%u",
oldto,
olddest4d.Zone,
olddest4d.Net,
olddest4d.Node,
olddest4d.Point);
oldlist.First=mm->TextChunks.First;
oldlist.Last=mm->TextChunks.Last;
jbNewList(&mm->TextChunks);
Copy4D(&mm->DestNode,&newdest4d);
strcpy(mm->To,newto);
MakeNetmailKludges(mm);
for(tmp=(struct TextChunk *)oldlist.First;tmp;tmp=tmp->Next)
{
c=0;
while(c<tmp->Length)
{
for(d=c;d<tmp->Length && tmp->Data[d]!=13;d++);
if(tmp->Data[d]==13) d++;
skip=FALSE;
if(d-c > 5)
{
if(strncmp(&tmp->Data[c],"\x01""INTL",5)==0) skip=TRUE;
if(strncmp(&tmp->Data[c],"\x01""FMPT",5)==0) skip=TRUE;
if(strncmp(&tmp->Data[c],"\x01""TOPT",5)==0) skip=TRUE;
}
if(d-c!=0 && !skip)
mmAddBuf(&mm->TextChunks,&tmp->Data[c],d-c);
c=d;
}
}
sprintf(buf,"\x01Remapped to %s at %u:%u/%u.%u by %u:%u/%u.%u\x0d",
newto,
newdest4d.Zone,
newdest4d.Net,
newdest4d.Node,
newdest4d.Point,
my4d.Zone,
my4d.Net,
my4d.Node,
my4d.Point);
mmAddLine(mm,buf);
sprintf(buf,"\x01Message originally to %s at %u:%u/%u.%ud",
oldto,
olddest4d.Zone,
olddest4d.Net,
olddest4d.Node,
olddest4d.Point);
mmAddLine(mm,buf);
jbFreeList(&oldlist);
if(nomem)
return(FALSE);
return(TRUE);
}
bool Filter(struct MemMessage *mm)
{
struct Filter *filter;
struct Command *command;
struct expr *expr;
char *errstr;
int errpos,res;
for(filter=(struct Filter *)config.FilterList.First;filter;filter=filter->Next)
{
if(!(expr=expr_makeexpr(filter->Filter)))
{
nomem=TRUE;
return(FALSE);
}
filter_mm=mm;
res=expr_eval(expr,filter_evalfunc,&errpos,&errstr);
expr_free(expr);
if(res == -1)
{
/* Error. All these should be caught in config.c/CheckConfig() */
LogWrite(3,TOSSINGERR,"Syntax error in filter");
return(TRUE);
}
if(res == 1)
{
/* Matches filter */
for(command=(struct Command *)filter->CommandList.First;command;command=command->Next)
{
switch(command->Cmd)
{
case COMMAND_KILL:
Filter_Kill(mm);
break;
case COMMAND_TWIT:
Filter_Twit(mm);
break;
case COMMAND_COPY:
Filter_Copy(mm,command->string);
break;
case COMMAND_EXECUTE:
if(!Filter_Execute(mm,command->string))
return(FALSE);
break;
case COMMAND_WRITELOG:
if(!Filter_WriteLog(mm,command->string))
return(FALSE);
break;
case COMMAND_WRITEBAD:
if(!Filter_WriteBad(mm,command->string))
return(FALSE);
break;
case COMMAND_BOUNCEMSG:
if(!Filter_Bounce(mm,command->string,FALSE))
return(FALSE);
break;
case COMMAND_BOUNCEHEADER:
if(!Filter_Bounce(mm,command->string,TRUE))
return(FALSE);
break;
case COMMAND_REMAPMSG:
if(!Filter_Remap(mm,command->string,&command->n4ddestpat))
return(FALSE);
break;
}
if(mm->Flags & MMFLAG_KILL)
return(TRUE);
}
}
}
return(TRUE);
}
bool CheckFilter(char *filter,char *cfgerr)
{
struct expr *expr;
char *errstr;
int errpos,res;
struct MemMessage *mm;
int c;
if(!(expr=expr_makeexpr(filter)))
{
nomem=TRUE;
return(FALSE);
}
if(!(mm=mmAlloc()))
{
expr_free(expr);
return(FALSE);
}
filter_mm=mm;
res=expr_eval(expr,filter_evalfunc,&errpos,&errstr);
expr_free(expr);
mmFree(mm);
if(res == -1)
{
if(strlen(filter) > 200)
{
strcpy(cfgerr,"Syntax error in filter");
}
else
{
sprintf(cfgerr," Syntax error in filter:\n %s\n",filter);
for(c=0;c<errpos+2;c++)
strcat(cfgerr," ");
strcat(cfgerr,"^");
strcat(cfgerr,"\n");
strcat(cfgerr," ");
strcat(cfgerr,errstr);
return(FALSE);
}
}
return(TRUE);
}

View File

@ -0,0 +1,4 @@
bool Filter(struct MemMessage *mm);
bool CheckFilter(char *filter,char *cfgerr);

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,7 @@
bool HandleMessage(struct MemMessage *mm);
bool HandleRescan(struct MemMessage *mm);
struct Area *AddArea(char *name,struct Node4D *node,struct Node4D *mynode,uint32_t active,uint32_t forcepassthru);
bool AddTossNode(struct Area *area,struct ConfigNode *cnode,uint16_t flags);
bool WriteBad(struct MemMessage *mm,char *reason);
bool Bounce(struct MemMessage *mm,char *reason,bool headeronly);

View File

@ -0,0 +1,134 @@
#include "magimail.h"
#ifdef OS_HAS_SYSLOG
#include <syslog.h>
bool usesyslog;
int syslogpri[] = { LOG_INFO, /* SYSTEMINFO */
LOG_ERR, /* SYSTEMERR */
LOG_INFO, /* TOSSINGINFO */
LOG_ERR, /* TOSSINGERR */
LOG_INFO, /* MISCINFO */
LOG_DEBUG, /* DEBUG */
LOG_INFO, /* AREAFIX */
LOG_INFO, /* ACTIONINFO */
LOG_ERR /* USERERR */
};
#endif
osFile logfh;
bool OpenLogfile(char *logfile)
{
#ifdef OS_HAS_SYSLOG
if(stricmp(logfile,"syslog")==0)
{
usesyslog=TRUE;
openlog("MagiMail",0,LOG_USER);
return(TRUE);
}
#endif
if(!(logfh=osOpen(logfile,MODE_READWRITE)))
{
uint32_t err=osError();
printf("Failed to open logfile %s\n",config.cfg_LogFile);
printf("Error: %s\n",osErrorMsg(err));
return(FALSE);
}
osSeek(logfh,0,OFFSET_END);
return(TRUE);
}
void CloseLogfile(void)
{
#ifdef OS_HAS_SYSLOG
if(usesyslog)
{
closelog();
usesyslog=FALSE;
return;
}
#endif
osClose(logfh);
}
char *categoryletters="-%=!/D+^?";
void LogWrite(uint32_t level,uint32_t category,char *fmt,...)
{
va_list args;
time_t t;
struct tm *tp;
char *monthnames[]={"Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec","???"};
char buf[500];
int i;
if(level > config.cfg_LogLevel)
return;
if(level == 0)
LogWrite(6,DEBUG,"*** Warning: Loglevel is 0!!! ***");
if(fmt[0]==0)
{
printf("\n");
return;
}
if(handle_nesting > 1 && handle_nesting + strlen(fmt) < 499)
{
buf[0]=0;
for(i=1;i<handle_nesting;i++)
strcat(buf," ");
strcat(buf,fmt);
fmt=buf;
}
#ifdef OS_HAS_SYSLOG
if(usesyslog)
{
va_start(args, fmt);
vprintf(fmt,args);
printf("\n");
va_end(args);
va_start(args, fmt);
vsyslog(syslogpri[category],fmt,args);
va_end(args);
return;
}
#endif
va_start(args, fmt);
vprintf(fmt,args);
printf("\n");
va_end(args);
time(&t);
tp=localtime(&t);
osFPrintf(logfh,"%c %02d-%s-%02d %02d:%02d:%02d ",
categoryletters[category],
tp->tm_mday,
monthnames[tp->tm_mon],
tp->tm_year%100,
tp->tm_hour,
tp->tm_min,
tp->tm_sec);
va_start(args, fmt);
osVFPrintf(logfh,fmt,args);
osFPrintf(logfh,"\n");
va_end(args);
}

View File

@ -0,0 +1,15 @@
#include <shared/types.h>
#define SYSTEMINFO 0
#define SYSTEMERR 1
#define TOSSINGINFO 2
#define TOSSINGERR 3
#define MISCINFO 4
#define DEBUG 5
#define AREAFIX 6
#define ACTIONINFO 7
#define USERERR 8
bool OpenLogfile(char *filename);
void CloseLogfile(void);
void LogWrite(uint32_t level,uint32_t category,char *fmt,...);

View File

@ -0,0 +1,720 @@
#include "magimail.h"
#ifdef PLATFORM_AMIGA
const char ver[]="\0$VER: MagiMail/" OS_PLATFORM_NAME " " VERSION " " __AMIGADATE__;
#endif
/*********************************** Global *******************************/
struct jbList PktList;
struct jbList DeleteList;
bool nomem;
bool ioerror;
uint32_t ioerrornum;
uint32_t toss_read;
uint32_t toss_bad;
uint32_t toss_route;
uint32_t toss_import;
uint32_t toss_written;
uint32_t toss_dupes;
uint32_t scan_total;
uint32_t rescan_total;
bool no_security;
int handle_nesting;
struct ConfigNode *RescanNode;
uint32_t DayStatsWritten; /* The area statistics are updated until this day */
struct Config config;
bool ctrlc;
bool nodelistopen;
char *prinames[]={"Normal","Hold","Normal","Direct","Crash"};
/**************************** Local for this file ****************************/
#define ARG_SCAN 0
#define ARG_TOSS 1
#define ARG_TOSSFILE 2
#define ARG_TOSSDIR 3
#define ARG_SCANAREA 4
#define ARG_SCANLIST 5
#define ARG_SCANDOTJAM 6
#define ARG_RESCAN 7
#define ARG_RESCANNODE 8
#define ARG_RESCANMAX 9
#define ARG_SENDQUERY 10
#define ARG_SENDLIST 11
#define ARG_SENDUNLINKED 12
#define ARG_SENDHELP 13
#define ARG_SENDINFO 14
#define ARG_REMOVE 15
#define ARG_SETTINGS 16
#define ARG_VERSION 17
#define ARG_LOCK 18
#define ARG_UNLOCK 19
#define ARG_NOSECURITY 20
struct argument args[] =
{ { ARGTYPE_BOOL, "SCAN", 0, 0 },
{ ARGTYPE_BOOL, "TOSS", 0, 0 },
{ ARGTYPE_STRING, "TOSSFILE", 0, NULL },
{ ARGTYPE_STRING, "TOSSDIR", 0, NULL },
{ ARGTYPE_STRING, "SCANAREA", 0, NULL },
{ ARGTYPE_STRING, "SCANLIST", 0, NULL },
{ ARGTYPE_STRING, "SCANDOTJAM", 0, NULL },
{ ARGTYPE_STRING, "RESCAN", 0, NULL },
{ ARGTYPE_STRING, "RESCANNODE", 0, NULL },
{ ARGTYPE_STRING, "RESCANMAX", 0, NULL },
{ ARGTYPE_STRING, "SENDQUERY", 0, NULL },
{ ARGTYPE_STRING, "SENDLIST", 0, NULL },
{ ARGTYPE_STRING, "SENDUNLINKED", 0, NULL },
{ ARGTYPE_STRING, "SENDHELP", 0, NULL },
{ ARGTYPE_STRING, "SENDINFO", 0, NULL },
{ ARGTYPE_STRING, "REMOVE", 0, NULL },
{ ARGTYPE_STRING, "SETTINGS", 0, NULL },
{ ARGTYPE_BOOL, "VERSION", 0, 0 },
{ ARGTYPE_BOOL, "LOCK", 0, 0 },
{ ARGTYPE_BOOL, "UNLOCK", 0, 0 },
{ ARGTYPE_BOOL, "NOSECURITY", 0, 0 },
{ ARGTYPE_END, NULL, 0, 0 } };
bool init_openlog;
bool init_dupedb;
void Free(void)
{
if(init_dupedb)
{
CloseDupeDB();
init_dupedb=0;
}
if(init_openlog)
{
CloseLogfile();
init_openlog=FALSE;
}
jbFreeList(&PktList);
jbFreeList(&DeleteList);
}
bool Init(void)
{
struct Area *area;
if(!OpenLogfile(config.cfg_LogFile))
{
Free();
return(FALSE);
}
init_openlog=TRUE;
if(config.cfg_DupeMode!=DUPE_IGNORE)
{
if(!OpenDupeDB())
{
Free();
return(FALSE);
}
init_dupedb=TRUE;
}
if(!ReadStats(config.cfg_StatsFile))
return(FALSE);
nomem=FALSE;
ioerror=FALSE;
for(area=(struct Area *)config.AreaList.First;area;area=area->Next)
if(area->Messagebase) area->Messagebase->active=TRUE;
return(TRUE);
}
void AfterScanToss(bool success)
{
struct Area *area;
struct ConfigNode *cnode;
char errbuf[200];
uint32_t day,d,e,i;
ClosePackets();
if(success)
{
ArchiveOutbound();
ProcessSafeDelete();
}
for(i=0;AvailMessagebases[i].name;i++)
if(AvailMessagebases[i].active && AvailMessagebases[i].afterfunc)
(*AvailMessagebases[i].afterfunc)(success);
if(success)
{
/* Rotate last8 if needed */
if(DayStatsWritten == 0) /* First time we use this statsfile */
DayStatsWritten = time(NULL) / (24*60*60);
day=time(NULL) / (24*60*60);
for(area=(struct Area *)config.AreaList.First;area;area=area->Next)
if(day > DayStatsWritten)
{
for(d=DayStatsWritten;d<day;d++)
{
for(e=0;e<7;e++)
area->Last8Days[7-e]=area->Last8Days[7-e-1];
area->Last8Days[0]=0;
}
}
DayStatsWritten=day;
/* Areas */
for(area=(struct Area *)config.AreaList.First;area;area=area->Next)
if(area->NewTexts || area->NewDupes)
{
area->Texts+=area->NewTexts;
area->Last8Days[0]+=area->NewTexts;
area->Dupes+=area->NewDupes;
if(area->NewTexts)
area->LastTime=time(NULL);
if(area->NewTexts && area->FirstTime==0)
area->FirstTime=time(NULL);
}
for(cnode=(struct ConfigNode *)config.CNodeList.First;cnode;cnode=cnode->Next)
{
if(cnode->FirstTime==0 && (cnode->GotEchomails!=0 || cnode->GotNetmails!=0 || cnode->SentEchomails!=0 || cnode->SentNetmails)!=0)
cnode->FirstTime=time(NULL);
}
WriteStats(config.cfg_StatsFile);
if(config.changed)
{
LogWrite(2,SYSTEMINFO,"Updating configuration file \"%s\"",config.filename);
if(!UpdateConfig(&config,errbuf))
LogWrite(1,SYSTEMERR,errbuf);
}
}
if(config.cfg_NodelistType)
(*config.cfg_NodelistType->nlEnd)();
nodelistopen=FALSE;
jbFreeList(&PktList);
jbFreeList(&DeleteList);
}
bool BeforeScanToss(void)
{
struct Area *area;
struct jbList NewPktFEList;
struct osFileEntry *fe;
char buf[200];
int i;
/* Open nodelist */
if(config.cfg_NodelistType)
{
if(!(*config.cfg_NodelistType->nlStart)(buf))
{
LogWrite(1,SYSTEMERR,"%s",buf);
return(FALSE);
}
nodelistopen=TRUE;
}
toss_read=0;
toss_bad=0;
toss_route=0;
toss_import=0;
toss_dupes=0;
toss_written=0;
scan_total=0;
handle_nesting=0;
for(area=(struct Area *)config.AreaList.First;area;area=area->Next)
{
area->NewDupes=0;
area->NewTexts=0;
area->scanned=FALSE;
}
jbNewList(&PktList); /* Created packets */
jbNewList(&DeleteList); /* For SafeDelete() */
/* Delete orphan files */
if(!osReadDir(config.cfg_PacketCreate,&NewPktFEList,IsNewPkt))
{
uint32_t err=osError();
LogWrite(1,SYSTEMERR,"Failed to read directory \"%s\"",config.cfg_PacketCreate);
LogWrite(1,SYSTEMERR,"Error: %s",osErrorMsg(err));
if(config.cfg_NodelistType)
(*config.cfg_NodelistType->nlEnd)();
nodelistopen=FALSE;
return(FALSE);
}
for(fe=(struct osFileEntry *)NewPktFEList.First;fe;fe=fe->Next)
{
LogWrite(1,SYSTEMINFO,"Deleting orphan tempfile %s",fe->Name);
MakeFullPath(config.cfg_PacketCreate,fe->Name,buf,200);
osDelete(buf);
}
jbFreeList(&NewPktFEList);
for(i=0;AvailMessagebases[i].name;i++)
if(AvailMessagebases[i].active)
{
if(AvailMessagebases[i].beforefunc)
if(!(*AvailMessagebases[i].beforefunc)())
{
if(config.cfg_NodelistType)
(*config.cfg_NodelistType->nlEnd)();
nodelistopen=FALSE;
return(FALSE);
}
}
return(TRUE);
}
void Version(void)
{
int i;
printf("This is MagiMail version %s\n",VERSION);
printf("\n");
printf("Operating system: %s\n",OS_PLATFORM_NAME);
printf("Compilation date: %s\n",__DATE__);
printf("Compilation time: %s\n",__TIME__);
printf("\n");
printf("Available messagebase formats:\n");
for(i=0;AvailMessagebases[i].name;i++)
printf(" %-10.10s %s\n",AvailMessagebases[i].name,AvailMessagebases[i].desc);
printf("\n");
printf("Available nodelist formats:\n");
for(i=0;AvailNodelists[i].name;i++)
printf(" %-10.10s %s\n",AvailNodelists[i].name,AvailNodelists[i].desc);
}
bool Rescan(char *areaname,char *node,uint32_t max)
{
struct Area *area;
struct ConfigNode *cnode;
struct Node4D n4d;
bool success;
if(!Parse4D(node,&n4d))
{
LogWrite(1,USERERR,"Invalid node number %s",node);
return(FALSE);
}
for(cnode=(struct ConfigNode *)config.CNodeList.First;cnode;cnode=cnode->Next)
if(Compare4D(&cnode->Node,&n4d)==0) break;
if(!cnode)
{
LogWrite(1,USERERR,"Unknown node %u:%u/%u.%u",n4d.Zone,n4d.Net,n4d.Node,n4d.Point);
return(FALSE);
}
for(area=(struct Area *)config.AreaList.First;area;area=area->Next)
if(stricmp(areaname,area->Tagname)==0) break;
if(!area)
{
LogWrite(1,USERERR,"Unknown area %s",areaname);
return(FALSE);
}
if(area->AreaType != AREATYPE_ECHOMAIL)
{
LogWrite(1,USERERR,"Area %s is not an echomail area",area->Tagname);
return(FALSE);
}
if(!area->Messagebase)
{
LogWrite(1,USERERR,"Can't rescan %s, area is pass-through",areaname);
return(FALSE);
}
if(!area->Messagebase->rescanfunc)
{
LogWrite(1,USERERR,"Can't rescan %s, messagebase does not support rescan",areaname);
return(FALSE);
}
if(!BeforeScanToss())
return(FALSE);
RescanNode=cnode;
rescan_total=0;
success=(*area->Messagebase->rescanfunc)(area,max,HandleRescan);
RescanNode=NULL;
if(success)
LogWrite(4,TOSSINGINFO,"Rescanned %u messages",rescan_total);
AfterScanToss(success);
return(success);
}
bool SendAFList(char *node,short type)
{
struct Node4D n4d;
struct ConfigNode *cnode;
if(!BeforeScanToss())
return(FALSE);
if(stricmp(node,"ALL")==0)
{
for(cnode=(struct ConfigNode *)config.CNodeList.First;cnode;cnode=cnode->Next)
if(cnode->Flags & NODE_NOTIFY) DoSendAFList(type,cnode);
}
else
{
if(!Parse4D(node,&n4d))
{
LogWrite(1,USERERR,"Invalid node number \"%s\"",node);
return(FALSE);
}
for(cnode=(struct ConfigNode *)config.CNodeList.First;cnode;cnode=cnode->Next)
if(Compare4D(&cnode->Node,&n4d)==0) break;
if(cnode)
{
DoSendAFList(type,cnode);
}
else
{
LogWrite(1,USERERR,"Unknown node %u:%u/%u.%u",n4d.Zone,n4d.Net,n4d.Node,n4d.Point);
return(FALSE);
}
}
AfterScanToss(TRUE);
if(nomem || ioerror)
return(FALSE);
return(TRUE);
}
bool RemoveArea(char *areaname)
{
struct Area *area;
if(!BeforeScanToss())
return(FALSE);
for(area=(struct Area *)config.AreaList.First;area;area=area->Next)
if(area->AreaType == AREATYPE_ECHOMAIL)
if(stricmp(areaname,area->Tagname)==0) break;
if(!area)
{
LogWrite(1,USERERR,"Unknown area %s",areaname);
return(TRUE);
}
LogWrite(1,AREAFIX,"AreaFix: Removing area %s",area->Tagname);
SendRemoveMessages(area);
area->AreaType=AREATYPE_DELETED;
RemoveDeletedAreas();
AfterScanToss(TRUE);
return(TRUE);
}
bool done_initconfig;
bool done_osinit;
bool done_welcomemsg;
bool done_init;
bool done_lockconfig;
bool LockConfig(char *file)
{
char buf[200];
osFile fp;
strcpy(buf,file);
strcat(buf,".busy");
while(osExists(buf))
{
printf("Configuration file %s is already in use, waiting 10 seconds...\n",file);
osSleep(10);
if(ctrlc)
return(FALSE);
}
if(!(fp=osOpen(buf,MODE_NEWFILE)))
{
printf("Failed to create lock file %s\n",buf);
return(FALSE);
}
osClose(fp);
return(TRUE);
}
void UnlockConfig(char *file)
{
char buf[200];
strcpy(buf,file);
strcat(buf,".busy");
osDelete(buf);
}
void CleanUp(int err)
{
if(done_welcomemsg)
LogWrite(2,SYSTEMINFO,"MagiMail end");
if(done_lockconfig)
UnlockConfig(config.filename);
if(done_init)
Free();
if(done_initconfig)
FreeConfig(&config);
if(done_osinit)
osEnd();
exit(err);
}
void breakfunc(int x)
{
ctrlc=TRUE;
}
int main(int argc, char **argv)
{
char *cfg;
uint32_t cfgline;
short seconderr;
char errorbuf[500];
signal(SIGINT,breakfunc);
if(!osInit())
CleanUp(OS_EXIT_ERROR);
done_osinit=TRUE;
if(argc > 1 &&
(strcmp(argv[1],"?")==0 ||
strcmp(argv[1],"-h")==0 ||
strcmp(argv[1],"--help")==0 ||
strcmp(argv[1],"help")==0 ||
strcmp(argv[1],"/h")==0 ||
strcmp(argv[1],"/?")==0 ))
{
printargs(args);
CleanUp(OS_EXIT_OK);
}
if(!parseargs(args,argc,argv))
CleanUp(OS_EXIT_ERROR);
if(args[ARG_VERSION].data)
{
Version();
CleanUp(OS_EXIT_OK);
}
cfg=getenv(OS_CONFIG_VAR);
if(!cfg)
cfg=OS_CONFIG_NAME;
if(args[ARG_SETTINGS].data)
cfg=(char *)args[ARG_SETTINGS].data;
if(args[ARG_LOCK].data)
{
if(!LockConfig(cfg))
{
printf("Failed to lock configuration file %s\n",cfg);
CleanUp(OS_EXIT_ERROR);
}
printf("MagiMail is now locked, use UNLOCK to unlock\n");
CleanUp(OS_EXIT_OK);
}
if(args[ARG_UNLOCK].data)
{
UnlockConfig(cfg);
CleanUp(OS_EXIT_OK);
}
InitConfig(&config);
done_initconfig=TRUE;
if(!(done_lockconfig=LockConfig(cfg)))
{
printf("Failed to lock configuration file %s\n",cfg);
CleanUp(OS_EXIT_ERROR);
}
if(!ReadConfig(cfg,&config,&seconderr,&cfgline,errorbuf))
{
if(seconderr == READCONFIG_INVALID)
printf("Configuration error in %s on line %d:\n%s\n",cfg,cfgline,errorbuf);
else if(seconderr == READCONFIG_NO_MEM)
printf("Out of memory\n");
else
printf("Failed to read configuration file %s\n",cfg);
CleanUp(OS_EXIT_ERROR);
}
if(!CheckConfig(&config,errorbuf))
{
printf("Configuration error in %s:\n%s\n",cfg,errorbuf);
CleanUp(OS_EXIT_ERROR);
}
if(!Init())
CleanUp(OS_EXIT_ERROR);
done_init=TRUE;
LogWrite(2,SYSTEMINFO,"MagiMail %s started successfully!",VERSION);
done_welcomemsg=TRUE;
no_security=FALSE;
if(args[ARG_NOSECURITY].data)
{
LogWrite(2,TOSSINGINFO,"Packets will be tossed without security checks");
no_security=TRUE;
}
if(args[ARG_TOSS].data)
TossDir(config.cfg_Inbound);
else if(args[ARG_TOSSFILE].data)
TossFile((char *)args[ARG_TOSSFILE].data);
if(args[ARG_TOSSDIR].data)
TossDir((char *)args[ARG_TOSSDIR].data);
else if(args[ARG_SCAN].data)
Scan();
else if(args[ARG_SCANAREA].data)
ScanArea((char *)args[ARG_SCANAREA].data);
else if(args[ARG_SCANLIST].data)
ScanList((char *)args[ARG_SCANLIST].data);
else if(args[ARG_SCANDOTJAM].data)
ScanDotJam((char *)args[ARG_SCANDOTJAM].data);
else if(args[ARG_RESCAN].data)
{
uint32_t num;
num=0;
if(args[ARG_RESCANMAX].data)
num=atoi((char *)args[ARG_RESCANMAX].data);
if(!args[ARG_RESCANNODE].data)
LogWrite(1,USERERR,"No RESCANNODE specified");
else
Rescan((char *)args[ARG_RESCAN].data,(char *)args[ARG_RESCANNODE].data,num);
}
else if(args[ARG_SENDLIST].data)
SendAFList((char *)args[ARG_SENDLIST].data,SENDLIST_FULL);
else if(args[ARG_SENDQUERY].data)
SendAFList((char *)args[ARG_SENDQUERY].data,SENDLIST_QUERY);
else if(args[ARG_SENDUNLINKED].data)
SendAFList((char *)args[ARG_SENDUNLINKED].data,SENDLIST_UNLINKED);
else if(args[ARG_SENDHELP].data)
SendAFList((char *)args[ARG_SENDHELP].data,SENDLIST_HELP);
else if(args[ARG_SENDINFO].data)
SendAFList((char *)args[ARG_SENDINFO].data,SENDLIST_INFO);
else if(args[ARG_REMOVE].data)
RemoveArea((char *)args[ARG_REMOVE].data);
if(nomem)
LogWrite(1,SYSTEMERR,"Out of memory");
if(ioerror)
LogWrite(1,SYSTEMERR,"I/O error: %s",osErrorMsg(ioerrornum));
if(ctrlc)
LogWrite(1,SYSTEMERR,"*** User break ***");
CleanUp(OS_EXIT_OK);
/* The next line is never actually executed. It is just there to stop gcc
from giving a warning. */
return(0);
}

View File

@ -0,0 +1,89 @@
#include <stdarg.h>
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
#include <signal.h>
#include <shared/types.h>
#include <shared/parseargs.h>
#include <shared/jblist.h>
#include <shared/mystrncpy.h>
#include <shared/jbstrcpy.h>
#include <shared/path.h>
#include <shared/node4d.h>
#include <shared/expr.h>
#include <oslib/os.h>
#include <oslib/osmem.h>
#include <oslib/osfile.h>
#include <oslib/osdir.h>
#include <oslib/ospattern.h>
#include <oslib/osmisc.h>
#include <shared/fidonet.h>
#include <shared/storedmsg.h>
#include "node4dpat.h"
#include "nl.h"
#include "mb.h"
#include "memmessage.h"
#include "config.h"
#include "memmessage.h"
#include "logwrite.h"
#include "dupe.h"
#include "stats.h"
#include "misc.h"
#include "safedel.h"
#include "toss.h"
#include "scan.h"
#include "pkt.h"
#include "handle.h"
#include "outbound.h"
#include "areafix.h"
#include "filter.h"
#include "version.h"
extern struct jbList PktList;
extern struct jbList DeleteList;
extern bool nomem;
extern bool ioerror;
extern uint32_t ioerrornum;
extern uint32_t toss_read;
extern uint32_t toss_bad;
extern uint32_t toss_route;
extern uint32_t toss_import;
extern uint32_t toss_written;
extern uint32_t toss_dupes;
extern uint32_t scan_total;
extern uint32_t rescan_total;
extern bool no_security;
extern int handle_nesting;
extern struct ConfigNode *RescanNode;
extern uint32_t DayStatsWritten;
extern struct Nodelist AvailNodelists[];
extern struct Messagebase AvailMessagebases[];
extern struct Config config;
extern bool ctrlc;
extern bool nodelistopen;
bool BeforeScanToss(void);
void AfterScanToss(bool success);
extern char *prinames[];

View File

@ -0,0 +1,56 @@
#include "magimail.h"
#ifdef MSGBASE_MSG
#include "mb_msg.h"
#endif
#ifdef MSGBASE_JAM
#include "mb_jam.h"
#endif
#ifdef MSGBASE_SQ3
#include "mb_sq3.h"
#endif
struct Messagebase AvailMessagebases[] =
{
#ifdef MSGBASE_MSG
{ "MSG",
"Standard *.msg messagebase as specified in FTS-1",
0,
msg_beforefunc,
msg_afterfunc,
msg_importfunc,
msg_exportfunc,
msg_rescanfunc },
#endif
#ifdef MSGBASE_JAM
{ "JAM",
"JAM Messagebase",
0,
jam_beforefunc,
jam_afterfunc,
jam_importfunc,
jam_exportfunc,
jam_rescanfunc },
#endif
#ifdef MSGBASE_SQ3
{ "SQ3",
"SQlite3 Messagebase",
0,
sq3_beforefunc,
sq3_afterfunc,
sq3_importfunc,
sq3_exportfunc,
sq3_rescanfunc },
#endif
{ NULL, /* NULL here marks the end of the array */
NULL,
0,
NULL,
NULL,
NULL,
NULL,
NULL
}
};

View File

@ -0,0 +1,20 @@
#ifndef MB_H
#define MB_H
#include "shared/types.h"
#include "memmessage.h"
#include "config.h"
struct Messagebase
{
char *name;
char *desc;
bool active;
bool (*beforefunc)(void);
bool (*afterfunc)(bool success);
bool (*importfunc)(struct MemMessage *mm,struct Area *area);
bool (*exportfunc)(struct Area *area,bool (*handlefunc)(struct MemMessage *mm));
bool (*rescanfunc)(struct Area *area,uint32_t max,bool (*handlefunc)(struct MemMessage *mm));
};
#endif

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,5 @@
bool jam_beforefunc(void);
bool jam_afterfunc(bool success);
bool jam_importfunc(struct MemMessage *mm,struct Area *area);
bool jam_exportfunc(struct Area *area,bool (*handlefunc)(struct MemMessage *mm));
bool jam_rescanfunc(struct Area *area,uint32_t max,bool (*handlefunc)(struct MemMessage *mm));

View File

@ -0,0 +1,593 @@
#include "magimail.h"
struct msg_Area
{
struct msg_Area *Next;
struct Area *area;
uint32_t LowMsg;
uint32_t HighMsg;
uint32_t OldHighWater;
uint32_t HighWater;
};
bool msg_GetHighLowMsg(struct msg_Area *area);
bool msg_WriteHighWater(struct msg_Area *area);
bool msg_WriteMSG(struct MemMessage *mm,char *file);
uint32_t msg_ReadCR(char *buf, uint32_t maxlen, osFile fh);
bool msg_ExportMSGNum(struct Area *area,uint32_t num,bool (*handlefunc)(struct MemMessage *mm),bool isrescanning);
struct jbList msg_AreaList;
bool msg_messageend;
bool msg_shortread;
struct msg_Area *msg_getarea(struct Area *area)
{
struct msg_Area *ma;
/* Check if area already exists */
for(ma=(struct msg_Area *)msg_AreaList.First;ma;ma=ma->Next)
if(ma->area == area) return(ma);
/* This is the first time we use this area */
if(!(ma=osAllocCleared(sizeof(struct msg_Area))))
{
nomem=TRUE;
return(FALSE);
}
jbAddNode(&msg_AreaList,(struct jbNode *)ma);
ma->area=area;
if(!msg_GetHighLowMsg(ma))
return(FALSE);
return(ma);
}
bool msg_beforefunc(void)
{
jbNewList(&msg_AreaList);
return(TRUE);
}
bool msg_afterfunc(bool success)
{
struct msg_Area *ma;
if(success && (config.cfg_msg_Flags & CFG_MSG_HIGHWATER))
for(ma=(struct msg_Area *)msg_AreaList.First;ma;ma=ma->Next)
if(ma->HighWater != ma->OldHighWater)
msg_WriteHighWater(ma);
return(TRUE);
}
bool msg_importfunc(struct MemMessage *mm,struct Area *area)
{
char buf[200],buf2[20];
struct msg_Area *ma;
if(!(ma=msg_getarea(area)))
return(FALSE);
ma->HighMsg++;
sprintf(buf2,"%u.msg",ma->HighMsg);
MakeFullPath(ma->area->Path,buf2,buf,200);
while(osExists(buf))
{
ma->HighMsg++;
sprintf(buf2,"%u.msg",ma->HighMsg);
MakeFullPath(ma->area->Path,buf2,buf,200);
}
return msg_WriteMSG(mm,buf);
}
bool msg_rescanfunc(struct Area *area,uint32_t max,bool (*handlefunc)(struct MemMessage *mm))
{
uint32_t start;
struct msg_Area *ma;
if(!(ma=msg_getarea(area)))
return(FALSE);
start=ma->LowMsg;
if(max !=0 && ma->HighMsg-start+1 > max)
start=ma->HighMsg-max+1;
while(start <= ma->HighMsg && !ctrlc)
{
if(!msg_ExportMSGNum(area,start,handlefunc,TRUE))
return(FALSE);
start++;
}
if(ctrlc)
return(FALSE);
return(TRUE);
}
bool msg_exportfunc(struct Area *area,bool (*handlefunc)(struct MemMessage *mm))
{
uint32_t start;
char buf[200];
struct StoredMsg Msg;
osFile fh;
struct msg_Area *ma;
if(!(ma=msg_getarea(area)))
return(FALSE);
if(config.cfg_msg_Flags & CFG_MSG_HIGHWATER)
{
if(ma->HighWater == 0)
{
MakeFullPath(area->Path,"1.msg",buf,200);
if((fh=osOpen(buf,MODE_OLDFILE)))
{
if((osRead(fh,&Msg,sizeof(struct StoredMsg))==sizeof(struct StoredMsg)))
{
ma->HighWater = Msg.ReplyTo;
ma->OldHighWater = Msg.ReplyTo;
}
osClose(fh);
}
}
}
if(ma->HighWater) start=ma->HighWater+1;
else start=ma->LowMsg;
if(start<ma->LowMsg)
start=ma->LowMsg;
while(start <= ma->HighMsg && !ctrlc)
{
if(!msg_ExportMSGNum(area,start,handlefunc,FALSE))
return(FALSE);
start++;
}
if(ctrlc)
return(FALSE);
return(TRUE);
}
bool msg_ExportMSGNum(struct Area *area,uint32_t num,bool (*handlefunc)(struct MemMessage *mm),bool isrescanning)
{
char buf[200],buf2[50];
bool kludgeadd;
osFile fh;
struct StoredMsg Msg;
struct MemMessage *mm;
uint16_t oldattr;
struct msg_Area *ma;
if(!(ma=msg_getarea(area)))
return(FALSE);
if(!(mm=mmAlloc()))
return(FALSE);
sprintf(buf2,"%u.msg",num);
MakeFullPath(area->Path,buf2,buf,200);
if(!(fh=osOpen(buf,MODE_OLDFILE)))
{
/* Message doesn't exist */
return(TRUE);
}
if(osRead(fh,&Msg,sizeof(struct StoredMsg))!=sizeof(struct StoredMsg))
{
LogWrite(1,TOSSINGERR,"Unexpected EOF while reading %s, message ignored",buf);
osClose(fh);
return(TRUE);
}
if(!isrescanning)
{
if((Msg.Attr & FLAG_SENT) || !(Msg.Attr & FLAG_LOCAL))
{
/* Don't touch if the message is sent or not local */
osClose(fh);
return(TRUE);
}
}
mm->OrigNode.Net=Msg.OrigNet;
mm->OrigNode.Node=Msg.OrigNode;
mm->DestNode.Net=Msg.DestNet;
mm->DestNode.Node=Msg.DestNode;
if(area->AreaType == AREATYPE_NETMAIL)
strcpy(mm->Area,"");
else
strcpy(mm->Area,area->Tagname);
mystrncpy(mm->To,Msg.To,36);
mystrncpy(mm->From,Msg.From,36);
mystrncpy(mm->Subject,Msg.Subject,72);
mystrncpy(mm->DateTime,Msg.DateTime,20);
oldattr = Msg.Attr;
mm->Attr = Msg.Attr & (FLAG_PVT|FLAG_CRASH|FLAG_FILEATTACH|FLAG_FILEREQ|FLAG_RREQ|FLAG_IRRR|FLAG_AUDIT|FLAG_HOLD);
mm->Cost = Msg.Cost;
kludgeadd=FALSE;
msg_messageend=FALSE;
msg_shortread=FALSE;
do
{
msg_ReadCR(buf,200,fh);
if(buf[0]!=1 && buf[0]!=10 && !kludgeadd)
{
kludgeadd=TRUE;
if((config.cfg_Flags & CFG_ADDTID) && !isrescanning)
AddTID(mm);
if(isrescanning)
{
sprintf(buf2,"\x01RESCANNED %u:%u/%u.%u\x0d",area->Aka->Node.Zone,
area->Aka->Node.Net,
area->Aka->Node.Node,
area->Aka->Node.Point);
mmAddLine(mm,buf2);
}
if(mm->Area[0]==0)
{
if(mm->DestNode.Zone == 0 || mm->OrigNode.Zone == 0)
{
/* No INTL line and no zone in header */
mm->DestNode.Zone=area->Aka->Node.Zone;
mm->OrigNode.Zone=area->Aka->Node.Zone;
Msg.DestZone=area->Aka->Node.Zone;
Msg.OrigZone=area->Aka->Node.Zone;
if(config.cfg_Flags & CFG_FORCEINTL)
{
sprintf(buf2,"\x01INTL %u:%u/%u %u:%u/%u\x0d",Msg.DestZone,Msg.DestNet,Msg.DestNode,
Msg.OrigZone,Msg.OrigNet,Msg.OrigNode);
mmAddLine(mm,buf2);
}
}
}
}
if(buf[0])
{
if(!mmAddLine(mm,buf))
{
osClose(fh);
mmFree(mm);
return(FALSE);
}
}
} while(!msg_messageend && !msg_shortread);
osClose(fh);
mm->msgnum=num;
if(isrescanning) mm->Flags |= MMFLAG_RESCANNED;
else mm->Flags |= MMFLAG_EXPORTED;
if(!(*handlefunc)(mm))
{
mmFree(mm);
return(FALSE);
}
if(!isrescanning)
{
scan_total++;
sprintf(buf2,"%u.msg",num);
MakeFullPath(area->Path,buf2,buf,200);
if((config.cfg_Flags & CFG_ALLOWKILLSENT) && (oldattr & FLAG_KILLSENT) && (area->AreaType == AREATYPE_NETMAIL))
{
/* Delete message with KILLSENT flag */
LogWrite(2,TOSSINGINFO,"Deleting message with KILLSENT flag");
osDelete(buf);
}
else
{
ma->HighWater=num;
Msg.Attr|=FLAG_SENT;
if(config.cfg_msg_Flags & CFG_MSG_WRITEBACK)
{
mm->Attr=Msg.Attr;
msg_WriteMSG(mm,buf);
}
else
{
if((fh=osOpen(buf,MODE_READWRITE)))
{
osWrite(fh,&Msg,sizeof(struct StoredMsg));
osClose(fh);
}
}
}
}
mmFree(mm);
return(TRUE);
}
uint32_t msg_templowmsg;
uint32_t msg_temphighmsg;
void msg_scandirfunc(char *file)
{
if(strlen(file) > 4)
{
if(stricmp(&file[strlen(file)-4],".msg")==0)
{
if(atol(file) > msg_temphighmsg)
msg_temphighmsg = atol(file);
if(atol(file) < msg_templowmsg || msg_templowmsg==0 ||msg_templowmsg==1)
if(atol(file) >= 2 ) msg_templowmsg=atol(file);
}
}
}
bool msg_GetHighLowMsg(struct msg_Area *area)
{
if(!osExists(area->area->Path))
{
LogWrite(2,SYSTEMINFO,"Creating directory \"%s\"",area->area->Path);
if(!osMkDir(area->area->Path))
{
uint32_t err=osError();
LogWrite(1,SYSTEMERR,"Unable to create directory");
LogWrite(1,SYSTEMERR,"Error: %s",osErrorMsg(err));
return(FALSE);
}
}
msg_templowmsg=0;
msg_temphighmsg=0;
if(!osScanDir(area->area->Path,msg_scandirfunc))
{
uint32_t err=osError();
LogWrite(1,SYSTEMERR,"Failed to scan directory %s",area->area->Path);
LogWrite(1,SYSTEMERR,"Error: %s",osErrorMsg(err));
return(FALSE);
}
area->HighMsg=msg_temphighmsg;
area->LowMsg=msg_templowmsg;
if(area->HighMsg==0)
area->HighMsg=1;
if(area->LowMsg==0 || area->LowMsg==1)
area->LowMsg=2;
return(TRUE);
}
bool msg_WriteHighWater(struct msg_Area *area)
{
osFile fh;
char buf[200];
struct StoredMsg Msg;
if(area->HighWater > 65535)
{
LogWrite(1,TOSSINGERR,"Warning: Highwater mark in %s exceeds 65535, cannot store in 1.msg",
area->area->Tagname);
return(TRUE);
}
strcpy(Msg.From,"MagiMail");
strcpy(Msg.To,"All");
strcpy(Msg.Subject,"HighWater mark");
MakeFidoDate(time(NULL),Msg.DateTime);
Msg.TimesRead=0;
Msg.DestNode=0;
Msg.OrigNode=0;
Msg.Cost=0;
Msg.OrigNet=0;
Msg.DestNet=0;
Msg.DestZone=0;
Msg.OrigZone=0;
Msg.OrigPoint=0;
Msg.DestPoint=0;
Msg.ReplyTo=area->HighWater;
Msg.Attr=FLAG_SENT | FLAG_PVT;
Msg.NextReply=0;
MakeFullPath(area->area->Path,"1.msg",buf,200);
if(!(fh=osOpen(buf,MODE_NEWFILE)))
{
uint32_t err=osError();
LogWrite(1,SYSTEMERR,"Failed to write Highwater mark to %s",buf);
LogWrite(1,SYSTEMERR,"Error: %s",osErrorMsg(err));
return(FALSE);
}
if(!osWrite(fh,&Msg,sizeof(struct StoredMsg)))
{ ioerror=TRUE; ioerrornum=osError(); }
if(!osWrite(fh,"",1))
{ ioerror=TRUE; ioerrornum=osError(); }
osClose(fh);
if(ioerror)
return(FALSE);
return(TRUE);
}
bool msg_WriteMSG(struct MemMessage *mm,char *file)
{
struct StoredMsg Msg;
struct TextChunk *chunk;
struct Path *path;
osFile fh;
int c;
strcpy(Msg.From,mm->From);
strcpy(Msg.To,mm->To);
strcpy(Msg.Subject,mm->Subject);
strcpy(Msg.DateTime,mm->DateTime);
Msg.TimesRead=0;
Msg.ReplyTo=0;
Msg.NextReply=0;
Msg.Cost= mm->Cost;
Msg.Attr= mm->Attr;
if(mm->Area[0]==0)
{
Msg.DestZone = mm->DestNode.Zone;
Msg.DestNet = mm->DestNode.Net;
Msg.DestNode = mm->DestNode.Node;
Msg.DestPoint = mm->DestNode.Point;
Msg.OrigZone = mm->OrigNode.Zone;
Msg.OrigNet = mm->OrigNode.Net;
Msg.OrigNode = mm->OrigNode.Node;
Msg.OrigPoint = mm->OrigNode.Point;
}
else
{
Msg.DestZone = 0;
Msg.DestNet = 0;
Msg.DestNode = 0;
Msg.DestPoint = 0;
Msg.OrigZone = 0;
Msg.OrigNet = 0;
Msg.OrigNode = 0;
Msg.OrigPoint = 0;
}
if(!(fh=osOpen(file,MODE_NEWFILE)))
{
printf("Failed to write to %s\n",file);
return(FALSE);
}
/* Write header */
if(!osWrite(fh,&Msg,sizeof(struct StoredMsg)))
{ ioerror=TRUE; ioerrornum=osError(); }
/* Write text */
for(chunk=(struct TextChunk *)mm->TextChunks.First;chunk;chunk=chunk->Next)
{
if(!osWrite(fh,chunk->Data,chunk->Length))
{ ioerror=TRUE; ioerrornum=osError(); }
}
/* Write seen-by */
if((config.cfg_Flags & CFG_IMPORTSEENBY) && mm->Area[0]!=0)
{
char *sbbuf;
if(!(sbbuf=mmMakeSeenByBuf(&mm->SeenBy)))
{
osClose(fh);
return(FALSE);
}
if(sbbuf[0])
{
if(!osWrite(fh,sbbuf,(uint32_t)strlen(sbbuf)))
{ ioerror=TRUE; ioerrornum=osError(); }
}
osFree(sbbuf);
}
/* Write path */
for(path=(struct Path *)mm->Path.First;path;path=path->Next)
for(c=0;c<path->Paths;c++)
if(path->Path[c][0]!=0)
{
if(!osWrite(fh,"\x01PATH: ",7))
{ ioerror=TRUE; ioerrornum=osError(); }
if(!osWrite(fh,path->Path[c],(uint32_t)strlen(path->Path[c])))
{ ioerror=TRUE; ioerrornum=osError(); }
if(!osWrite(fh,"\x0d",1))
{ ioerror=TRUE; ioerrornum=osError(); }
}
if(!osPutChar(fh,0))
{ ioerror=TRUE; ioerrornum=osError(); }
osClose(fh);
if(ioerror)
return(FALSE);
return(TRUE);
}
uint32_t msg_ReadCR(char *buf, uint32_t maxlen, osFile fh)
{
/* Reads from fh until buffer full or CR */
short ch,c=0;
ch=osGetChar(fh);
while(ch!=-1 && ch!=0 && ch!=10 && ch !=13 && c!=maxlen-2)
{
buf[c++]=ch;
if(c!=maxlen-2) ch=osGetChar(fh);
}
if(ch==13 || ch==10)
buf[c++]=ch;
buf[c]=0;
if(ch==0) msg_messageend=TRUE;
if(ch==-1) msg_shortread=TRUE;
return(c);
}

View File

@ -0,0 +1,5 @@
bool msg_beforefunc(void);
bool msg_afterfunc(bool success);
bool msg_importfunc(struct MemMessage *mm,struct Area *area);
bool msg_exportfunc(struct Area *area,bool (*handlefunc)(struct MemMessage *mm));
bool msg_rescanfunc(struct Area *area,uint32_t max,bool (*handlefunc)(struct MemMessage *mm));

View File

@ -0,0 +1,628 @@
#include <sqlite3.h>
#include "magimail.h"
long sq3_utcoffset;
#define MIN(a,b) ((a)<(b)? (a):(b))
void sq3_init_msg_db(char *dbpath) {
char *sql1 = "CREATE TABLE IF NOT EXISTS msgs ("
"id INTEGER PRIMARY KEY,"
"sender TEXT COLLATE NOCASE,"
"recipient TEXT COLLATE NOCASE,"
"subject TEXT,"
"oaddress TEXT,"
"daddress TEXT,"
"msgid TEXT,"
"replyid TEXT,"
"local INTEGER,"
"sent INTEGER,"
"private INTEGER,"
"datewritten INTEGER,"
"body TEXT);";
char *sql2 = "CREATE TABLE IF NOT EXISTS msgptrs ("
"id INTEGER PRIMARY KEY,"
"msgid INTEGER,"
"userid INTEGER);";
sqlite3 *db;
int rc;
char *errmsg;
rc = sqlite3_open(dbpath, &db);
sqlite3_busy_timeout(db, 10000);
if (rc != SQLITE_OK) {
sqlite3_close(db);
return;
}
rc = sqlite3_exec(db, sql1, 0, 0, &errmsg);
if (rc != SQLITE_OK) {
sqlite3_free(errmsg);
sqlite3_close(db);
return;
}
rc = sqlite3_exec(db, sql2, 0, 0, &errmsg);
if (rc != SQLITE_OK) {
sqlite3_free(errmsg);
sqlite3_close(db);
return;
}
}
bool sq3_beforefunc(void) {
time_t t1,t2;
struct tm *tp;
t1=time(NULL);
tp=gmtime(&t1);
tp->tm_isdst=-1;
t2=mktime(tp);
sq3_utcoffset=t2-t1;
return TRUE;
}
bool sq3_afterfunc(bool success) {
return TRUE;
}
bool sq3_importfunc(struct MemMessage *mm,struct Area *area) {
char buffer[1024];
sqlite3 *db;
sqlite3_stmt *res;
int rc;
char *sql = "INSERT INTO msgs (sender, recipient, subject, oaddress, daddress, msgid, replyid, local, sent, private, datewritten, body) VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)";
char *sender;
char *recipient;
char *subject;
char *oaddress;
char *daddress;
char *msgid;
char *replyid;
int local;
int sent;
int private;
time_t datewritten;
struct TextChunk *chunk;
uint32_t c,linebegin,linelen;
char *msgtext;
char *body;
uint32_t msgsize,msgpos;
if (mm->From[0]) {
sender = strdup(mm->From);
} else {
sender = NULL;
}
if (mm->To[0]) {
recipient = strdup(mm->To);
} else {
recipient = NULL;
}
if (mm->Subject[0]) {
subject = strdup(mm->Subject);
} else {
subject = NULL;
}
if(mm->Area[0] == 0) {
oaddress = (char *)osAlloc(100);
Print4D(&mm->OrigNode, oaddress);
daddress = (char *)osAlloc(100);
Print4D(&mm->DestNode, daddress);
private = 1;
} else {
oaddress = (char *)osAlloc(100);
Print4D(&mm->Origin4D, oaddress);
daddress = NULL;
private = 0;
}
datewritten = FidoToTime(mm->DateTime);
datewritten -= sq3_utcoffset;
local = 0;
sent = 0;
msgpos=0;
msgsize=0;
replyid = NULL;
msgid = NULL;
for(chunk=(struct TextChunk *)mm->TextChunks.First;chunk;chunk=chunk->Next)
msgsize+=chunk->Length;
if(msgsize != 0)
{
if(!(msgtext=osAlloc(msgsize)))
{
LogWrite(1,SYSTEMERR,"Out of memory");
return(FALSE);
}
}
/* Separate kludges from text */
for(chunk=(struct TextChunk *)mm->TextChunks.First;chunk;chunk=chunk->Next)
for(c=0;c<chunk->Length;)
{
linebegin=msgpos;
while(chunk->Data[c]!=13 && c<chunk->Length)
{
if(chunk->Data[c]!=10)
msgtext[msgpos++]=chunk->Data[c];
c++;
}
if(chunk->Data[c]==13 && c<chunk->Length)
msgtext[msgpos++]=chunk->Data[c++];
linelen=msgpos-linebegin;
if(linelen!=0)
{
if(linelen>=7 && strncmp(&msgtext[linebegin],"\x01""MSGID:",7)==0)
{
mystrncpy(buffer,&msgtext[linebegin+7],MIN(100,linelen-7));
stripleadtrail(buffer);
msgid = strdup(buffer);
msgpos=linebegin;
}
else if(linelen>=7 && strncmp(&msgtext[linebegin],"\x01""REPLY:",7)==0)
{
mystrncpy(buffer,&msgtext[linebegin+7],MIN(100,linelen-7));
stripleadtrail(buffer);
replyid = strdup(buffer);
msgpos=linebegin;
}
else if(linelen>=7 && strncmp(&msgtext[linebegin],"\x01""FLAGS:",7)==0)
{
msgpos=linebegin;
}
else if(linelen>=5 && strncmp(&msgtext[linebegin],"\x01""INTL",5)==0)
{
/* Remove this kludge */
msgpos=linebegin;
}
else if(linelen>=5 && strncmp(&msgtext[linebegin],"\x01""TOPT",5)==0)
{
/* Remove this kludge */
msgpos=linebegin;
}
else if(linelen>=5 && strncmp(&msgtext[linebegin],"\x01""FMPT",5)==0)
{
/* Remove this kludge */
msgpos=linebegin;
}
else if(msgtext[linebegin]==1)
{
msgpos=linebegin;
}
}
}
if (msgsize == 0) {
msgtext = "";
msgpos = 1;
}
body = (char *)osAlloc(msgpos + 1);
memset(body, 0, msgpos+1);
memcpy(body, msgtext, msgpos);
if (msgsize) {
osFree(msgtext);
}
snprintf(buffer, 1024, "%s.sq3", area->Path);
sq3_init_msg_db(buffer);
rc = sqlite3_open(buffer, &db);
sqlite3_busy_timeout(db, 10000);
if (rc != SQLITE_OK) {
sqlite3_close(db);
return FALSE;
}
rc = sqlite3_prepare_v2(db, sql, -1, &res, 0);
if (rc != SQLITE_OK) {
sqlite3_close(db);
return FALSE;
}
sqlite3_bind_text(res, 1, sender, -1, 0);
sqlite3_bind_text(res, 2, recipient, -1, 0);
sqlite3_bind_text(res, 3, subject, -1, 0);
sqlite3_bind_text(res, 4, oaddress, -1, 0);
sqlite3_bind_text(res, 5, daddress, -1, 0);
sqlite3_bind_text(res, 6, msgid, -1, 0);
sqlite3_bind_text(res, 7, replyid, -1, 0);
sqlite3_bind_int(res, 8, local);
sqlite3_bind_int(res, 9, sent);
sqlite3_bind_int(res, 10, private);
sqlite3_bind_int(res, 11, datewritten);
sqlite3_bind_text(res, 12, body, -1, 0);
sqlite3_step(res);
sqlite3_finalize(res);
sqlite3_close(db);
if (sender != NULL) {
osFree(sender);
}
if (recipient != NULL) {
osFree(recipient);
}
if (subject != NULL) {
osFree(subject);
}
if (oaddress != NULL) {
osFree(oaddress);
}
if (daddress != NULL) {
osFree(daddress);
}
if (msgid != NULL) {
osFree(msgid);
}
if (replyid != NULL) {
osFree(replyid);
}
osFree(body);
return TRUE;
}
void sq3_makekludge(struct MemMessage *mm,char *pre,char *data)
{
char *buf;
uint32_t len = strlen(data);
if(!(buf=osAlloc(strlen(pre)+len+10))) /* A few bytes extra */
return;
strcpy(buf,pre);
if(len && data) mystrncpy(&buf[strlen(buf)],data,len+1);
strcat(buf,"\x0d");
mmAddLine(mm,buf);
osFree(buf);
}
bool sq3_rescanfunc(struct Area *area,uint32_t max,bool (*handlefunc)(struct MemMessage *mm)) {
sqlite3 *db;
sqlite3_stmt *res;
int rc;
char *sql = "SELECT id, sender, recipient, subject, oaddress, daddress, msgid, replyid, local, sent, private, datewritten, body FROM msgs ORDER BY datewritten DESC LIMIT %d";
char buffer[1024];
struct MemMessage *mm;
char domain[20];
struct Node4D n4d;
char *msgtext;
snprintf(buffer, 1024, "%s.sq3", area->Path);
sq3_init_msg_db(buffer);
rc = sqlite3_open(buffer, &db);
sqlite3_busy_timeout(db, 10000);
if (rc != SQLITE_OK) {
sqlite3_close(db);
return FALSE;
}
sprintf(buffer, sql, max);
rc = sqlite3_prepare_v2(db, buffer, -1, &res, 0);
if (rc != SQLITE_OK) {
sqlite3_close(db);
return FALSE;
}
while (sqlite3_step(res) == SQLITE_ROW && !ctrlc) {
mm = mmAlloc();
if (area->AreaType == AREATYPE_NETMAIL) {
strcpy(mm->Area, "");
mm->Attr = FLAG_CRASH | FLAG_LOCAL | FLAG_PVT;
} else {
strcpy(mm->Area, area->Tagname);
mm->Attr = FLAG_CRASH | FLAG_LOCAL;
}
mm->msgnum = sqlite3_column_int(res, 0);
if (sqlite3_column_text(res, 1) != NULL) {
mystrncpy(mm->From, (char *)sqlite3_column_text(res, 1), 36);
}
if (sqlite3_column_text(res, 2) != NULL) {
mystrncpy(mm->To, (char *)sqlite3_column_text(res, 2), 36);
}
if (sqlite3_column_text(res, 3) != NULL) {
mystrncpy(mm->Subject, (char *)sqlite3_column_text(res, 3), 72);
}
if (sqlite3_column_text(res, 4) != NULL) {
if (Parse5D((char *)sqlite3_column_text(res, 4), &n4d, domain)) {
mm->OrigNode.Zone=n4d.Zone;
mm->OrigNode.Net=n4d.Net;
mm->OrigNode.Node=n4d.Node;
mm->OrigNode.Point=n4d.Point;
}
}
if (sqlite3_column_text(res, 5) != NULL) {
if (Parse5D((char *)sqlite3_column_text(res, 5), &n4d, domain)) {
mm->DestNode.Zone=n4d.Zone;
mm->DestNode.Net=n4d.Net;
mm->DestNode.Node=n4d.Node;
mm->DestNode.Point=n4d.Point;
}
}
if (sqlite3_column_text(res, 6) != NULL) {
sq3_makekludge(mm,"\x01" "MSGID: ", (char *)sqlite3_column_text(res, 6));
}
if (sqlite3_column_text(res, 7) != NULL) {
sq3_makekludge(mm, "\x01" "REPLY: ", (char *)sqlite3_column_text(res, 7));
}
MakeFidoDate(sqlite3_column_int(res, 11)+sq3_utcoffset,mm->DateTime);
msgtext = strdup((char *)sqlite3_column_text(res, 12));
mm->Cost = 0;
if(area->AreaType == AREATYPE_NETMAIL)
{
if(mm->OrigNode.Zone != mm->DestNode.Zone || (config.cfg_Flags & CFG_FORCEINTL))
{
sprintf(buffer,"\x01" "INTL %u:%u/%u %u:%u/%u\x0d",
mm->DestNode.Zone,
mm->DestNode.Net,
mm->DestNode.Node,
mm->OrigNode.Zone,
mm->OrigNode.Net,
mm->OrigNode.Node);
mmAddLine(mm,buffer);
}
if(mm->OrigNode.Point)
{
sprintf(buffer,"\x01" "FMPT %u\x0d",mm->OrigNode.Point);
mmAddLine(mm,buffer);
}
if(mm->DestNode.Point)
{
sprintf(buffer,"\x01" "TOPT %u\x0d",mm->DestNode.Point);
mmAddLine(mm,buffer);
}
sprintf(buffer,"\x01RESCANNED %u:%u/%u.%u\x0d",area->Aka->Node.Zone,
area->Aka->Node.Net,
area->Aka->Node.Node,
area->Aka->Node.Point);
mmAddLine(mm,buffer);
}
if(msgtext)
{
/* Extract origin address */
if(mm->Area[0])
{
uint32_t textpos,d;
char originbuf[200];
struct Node4D n4d;
textpos=0;
while(msgtext[textpos])
{
d=textpos;
while(msgtext[d] != 13 && msgtext[d] != 0)
d++;
if(msgtext[d] == 13)
d++;
if(d-textpos > 11 && strncmp(&msgtext[textpos]," * Origin: ",11)==0)
{
mystrncpy(originbuf,&msgtext[textpos],MIN(d-textpos,200));
if(ExtractAddress(originbuf,&n4d))
Copy4D(&mm->Origin4D,&n4d);
}
textpos=d;
}
}
if(!(mmAddBuf(&mm->TextChunks,msgtext,strlen(msgtext))))
{
osFree(msgtext);
mmFree(mm);
continue;
}
}
osFree(msgtext);
mm->Flags |= MMFLAG_RESCANNED;
if(!(*handlefunc)(mm)) {
mmFree(mm);
continue;
}
mmFree(mm);
}
sqlite3_close(db);
return TRUE;
}
bool sq3_exportfunc(struct Area *area,bool (*handlefunc)(struct MemMessage *mm)) {
sqlite3 *db;
sqlite3_stmt *res;
sqlite3_stmt *res2;
int rc;
char *sql = "SELECT id, sender, recipient, subject, oaddress, daddress, msgid, replyid, local, sent, private, datewritten, body FROM msgs WHERE local=1 and sent=0";
char *sql2 = "UPDATE msgs SET sent=1 WHERE id=?";
char buffer[1024];
struct MemMessage *mm;
char domain[20];
struct Node4D n4d;
char *msgtext;
snprintf(buffer, 1024, "%s.sq3", area->Path);
sq3_init_msg_db(buffer);
rc = sqlite3_open(buffer, &db);
sqlite3_busy_timeout(db, 10000);
if (rc != SQLITE_OK) {
sqlite3_close(db);
return FALSE;
}
rc = sqlite3_prepare_v2(db, sql, -1, &res, 0);
if (rc != SQLITE_OK) {
sqlite3_close(db);
return FALSE;
}
while (sqlite3_step(res) == SQLITE_ROW && !ctrlc) {
mm = mmAlloc();
if (area->AreaType == AREATYPE_NETMAIL) {
strcpy(mm->Area, "");
mm->Attr = FLAG_LOCAL | FLAG_PVT;
} else {
strcpy(mm->Area, area->Tagname);
mm->Attr = FLAG_CRASH | FLAG_LOCAL;
}
mm->msgnum = sqlite3_column_int(res, 0);
if (sqlite3_column_text(res, 1) != NULL) {
mystrncpy(mm->From, (char *)sqlite3_column_text(res, 1), 36);
}
if (sqlite3_column_text(res, 2) != NULL) {
mystrncpy(mm->To, (char *)sqlite3_column_text(res, 2), 36);
}
if (sqlite3_column_text(res, 3) != NULL) {
mystrncpy(mm->Subject, (char *)sqlite3_column_text(res, 3), 72);
}
if (sqlite3_column_text(res, 4) != NULL) {
if (Parse5D((char *)sqlite3_column_text(res, 4), &n4d, domain)) {
mm->OrigNode.Zone=n4d.Zone;
mm->OrigNode.Net=n4d.Net;
mm->OrigNode.Node=n4d.Node;
mm->OrigNode.Point=n4d.Point;
}
}
if (sqlite3_column_text(res, 5) != NULL) {
if (Parse5D((char *)sqlite3_column_text(res, 5), &n4d, domain)) {
mm->DestNode.Zone=n4d.Zone;
mm->DestNode.Net=n4d.Net;
mm->DestNode.Node=n4d.Node;
mm->DestNode.Point=n4d.Point;
}
}
if (sqlite3_column_text(res, 6) != NULL) {
sq3_makekludge(mm,"\x01" "MSGID: ",(char *)sqlite3_column_text(res, 6));
}
if (sqlite3_column_text(res, 7) != NULL) {
sq3_makekludge(mm, "\x01" "REPLY: ", (char *)sqlite3_column_text(res, 7));
}
MakeFidoDate(sqlite3_column_int(res, 11)+sq3_utcoffset,mm->DateTime);
msgtext = strdup((char *)sqlite3_column_text(res, 12));
mm->Cost = 0;
if(area->AreaType == AREATYPE_NETMAIL)
{
if(mm->OrigNode.Zone != mm->DestNode.Zone || (config.cfg_Flags & CFG_FORCEINTL))
{
sprintf(buffer,"\x01" "INTL %u:%u/%u %u:%u/%u\x0d",
mm->DestNode.Zone,
mm->DestNode.Net,
mm->DestNode.Node,
mm->OrigNode.Zone,
mm->OrigNode.Net,
mm->OrigNode.Node);
mmAddLine(mm,buffer);
}
if(mm->OrigNode.Point)
{
sprintf(buffer,"\x01" "FMPT %u\x0d",mm->OrigNode.Point);
mmAddLine(mm,buffer);
}
if(mm->DestNode.Point)
{
sprintf(buffer,"\x01" "TOPT %u\x0d",mm->DestNode.Point);
mmAddLine(mm,buffer);
}
}
if(config.cfg_Flags & CFG_ADDTID)
AddTID(mm);
if(msgtext)
{
/* Extract origin address */
if(mm->Area[0])
{
uint32_t textpos,d;
char originbuf[200];
struct Node4D n4d;
textpos=0;
while(msgtext[textpos])
{
d=textpos;
while(msgtext[d] != 13 && msgtext[d] != 0)
d++;
if(msgtext[d] == 13)
d++;
if(d-textpos > 11 && strncmp(&msgtext[textpos]," * Origin: ",11)==0)
{
mystrncpy(originbuf,&msgtext[textpos],MIN(d-textpos,200));
if(ExtractAddress(originbuf,&n4d))
Copy4D(&mm->Origin4D,&n4d);
}
textpos=d;
}
}
if(!(mmAddBuf(&mm->TextChunks,msgtext,strlen(msgtext))))
{
osFree(msgtext);
mmFree(mm);
continue;
}
}
osFree(msgtext);
mm->Flags |= MMFLAG_EXPORTED;
if(!(*handlefunc)(mm)) {
mmFree(mm);
continue;
}
scan_total++;
rc = sqlite3_prepare_v2(db, sql2, -1, &res2, 0);
if (rc != SQLITE_OK) {
mmFree(mm);
continue;
}
sqlite3_bind_int(res2, 1, mm->msgnum);
sqlite3_step(res2);
sqlite3_finalize(res2);
mmFree(mm);
}
sqlite3_close(db);
return TRUE;
}

View File

@ -0,0 +1,5 @@
bool sq3_beforefunc(void);
bool sq3_afterfunc(bool success);
bool sq3_importfunc(struct MemMessage *mm,struct Area *area);
bool sq3_exportfunc(struct Area *area,bool (*handlefunc)(struct MemMessage *mm));
bool sq3_rescanfunc(struct Area *area,uint32_t max,bool (*handlefunc)(struct MemMessage *mm));

View File

@ -0,0 +1,539 @@
#include "magimail.h"
bool mmAddNodes2DList(struct jbList *list,uint16_t net,uint16_t node)
{
/* Add a node to SEEN-BY list */
struct Nodes2D *tmplist;
uint16_t num;
/* Check if it already exists */
for(tmplist=(struct Nodes2D *)list->First;tmplist;tmplist=tmplist->Next)
{
for(num=0;num<tmplist->Nodes;num++)
if(tmplist->Net[num]==net && tmplist->Node[num]==node) return(TRUE);
}
tmplist=(struct Nodes2D *)list->Last;
if(tmplist && tmplist->Nodes == PKT_NUM2D)
tmplist=NULL;
if(!tmplist)
{
if(!(tmplist=(struct Nodes2D *)osAlloc(sizeof(struct Nodes2D))))
{
nomem=TRUE;
return(FALSE);
}
jbAddNode(list,(struct jbNode *)tmplist);
tmplist->Nodes=0;
tmplist->Next=NULL;
}
tmplist->Net[tmplist->Nodes]=net;
tmplist->Node[tmplist->Nodes]=node;
tmplist->Nodes++;
return(TRUE);
}
void mmRemNodes2DList(struct jbList *list,uint16_t net,uint16_t node)
{
/* Rem a node from SEEN-BY list */
struct Nodes2D *tmplist;
uint16_t num;
for(tmplist=(struct Nodes2D *)list->First;tmplist;tmplist=tmplist->Next)
for(num=0;num<tmplist->Nodes;num++)
if(tmplist->Net[num]==net && tmplist->Node[num]==num)
{
tmplist->Net[num]=0;
tmplist->Node[num]=0;
}
}
void mmRemNodes2DListPat(struct jbList *list,struct Node2DPat *pat)
{
struct Nodes2D *tmplist;
uint16_t num;
for(tmplist=(struct Nodes2D *)list->First;tmplist;tmplist=tmplist->Next)
for(num=0;num<tmplist->Nodes;num++)
{
if(Compare2DPat(pat,tmplist->Net[num],tmplist->Node[num])==0)
{
tmplist->Net[num]=0;
tmplist->Node[num]=0;
}
}
}
bool mmAddPath(char *str,struct jbList *list)
{
/* Add a node string to PATH list */
struct Path *path;
if(str[0]==0)
return(TRUE);
path=(struct Path *)list->Last;
if(path && path->Paths == PKT_NUMPATH)
path=NULL;
if(!path)
{
if(!(path=(struct Path *)osAlloc(sizeof(struct Path))))
{
nomem=TRUE;
return(FALSE);
}
jbAddNode(list,(struct jbNode *)path);
path->Paths=0;
path->Next=NULL;
}
mystrncpy(path->Path[path->Paths],str,100);
striptrail(path->Path[path->Paths]);
path->Paths++;
return(TRUE);
}
bool mmAddBuf(struct jbList *chunklist,char *buf,uint32_t len)
{
struct TextChunk *chunk,*oldchunk;
uint32_t copylen,d;
if(len == 0)
return(TRUE);
/* Find last chunk */
chunk=(struct TextChunk *)chunklist->Last;
/* Will it fit in this chunk?. If yes, copy and exit. */
if(chunk && chunk->Length+len <= PKT_CHUNKLEN)
{
memcpy(&chunk->Data[chunk->Length],buf,(size_t)len);
chunk->Length+=len;
return(TRUE);
}
/* We will need a new chunk */
while(len)
{
oldchunk=chunk;
if(!(chunk=(struct TextChunk *)osAlloc(sizeof(struct TextChunk))))
{
nomem=TRUE;
return(FALSE);
}
chunk->Length=0;
jbAddNode(chunklist,(struct jbNode *)chunk);
/* Copy over last line from old chunk if not complete */
if(oldchunk && oldchunk->Length > 0 && oldchunk->Data[oldchunk->Length-1] != 13)
{
for(d=oldchunk->Length-1;d>0;d--)
if(oldchunk->Data[d] == 13) break;
if(d != 0)
{
memcpy(chunk->Data,&oldchunk->Data[d+1],oldchunk->Length-d-1);
chunk->Length=oldchunk->Length-d-1;
oldchunk->Length=d+1;
}
}
copylen=len;
if(copylen > PKT_CHUNKLEN-chunk->Length) copylen=PKT_CHUNKLEN-chunk->Length;
memcpy(&chunk->Data[chunk->Length],buf,(size_t)copylen);
chunk->Length+=copylen;
buf=&buf[copylen];
len-=copylen;
}
return(TRUE);
}
struct MemMessage *mmAlloc(void)
{
struct MemMessage *mm;
mm=osAllocCleared(sizeof(struct MemMessage));
if(!mm)
{
osFree(mm);
nomem=TRUE;
return(NULL);
}
jbNewList(&mm->TextChunks);
jbNewList(&mm->SeenBy);
jbNewList(&mm->Path);
return(mm);
}
void mmClear(struct MemMessage *mm)
{
struct Node4D null4d = { 0,0,0,0 };
Copy4D(&mm->OrigNode,&null4d);
Copy4D(&mm->DestNode,&null4d);
Copy4D(&mm->PktOrig,&null4d);
Copy4D(&mm->PktDest,&null4d);
Copy4D(&mm->Origin4D,&null4d);
mm->Area[0]=0;
mm->To[0]=0;
mm->From[0]=0;
mm->Subject[0]=0;
mm->DateTime[0]=0;
mm->MSGID[0]=0;
mm->REPLY[0]=0;
mm->Attr=0;
mm->Cost=0;
mm->Type=0;
mm->Flags=0;
jbFreeList(&mm->TextChunks);
jbFreeList(&mm->SeenBy);
jbFreeList(&mm->Path);
}
void mmFree(struct MemMessage *mm)
{
jbFreeList(&mm->TextChunks);
jbFreeList(&mm->SeenBy);
jbFreeList(&mm->Path);
osFree(mm);
}
struct TempSort
{
uint16_t Net;
uint16_t Node;
};
int CompareSort(const void *t1,const void *t2)
{
if(((struct TempSort *)t1)->Net > ((struct TempSort *)t2)->Net)
return(1);
if(((struct TempSort *)t1)->Net < ((struct TempSort *)t2)->Net)
return(-1);
if(((struct TempSort *)t1)->Node > ((struct TempSort *)t2)->Node)
return(1);
if(((struct TempSort *)t1)->Node < ((struct TempSort *)t2)->Node)
return(-1);
return(0);
}
bool mmSortNodes2D(struct jbList *list)
{
struct Nodes2D *tmp;
struct TempSort *sorttemp;
uint32_t nodes=0;
uint32_t c,d;
for(tmp=(struct Nodes2D *)list->First;tmp;tmp=tmp->Next)
nodes+=tmp->Nodes;
if(nodes==0)
return(TRUE);
if(!(sorttemp=(struct TempSort *)osAlloc(sizeof(struct TempSort)*nodes)))
{
nomem=TRUE;
return(FALSE);
}
d=0;
for(tmp=(struct Nodes2D *)list->First;tmp;tmp=tmp->Next)
for(c=0;c<tmp->Nodes;c++)
{
sorttemp[d].Net=tmp->Net[c];
sorttemp[d].Node=tmp->Node[c];
d++;
}
qsort(sorttemp,(size_t)nodes,sizeof(struct TempSort),CompareSort);
tmp=(struct Nodes2D *)list->First;
tmp->Nodes=0;
for(c=0;c<nodes;c++)
{
if(tmp->Nodes == PKT_NUM2D)
{
tmp=tmp->Next;
tmp->Nodes=0;
}
tmp->Net[tmp->Nodes]=sorttemp[c].Net;
tmp->Node[tmp->Nodes]=sorttemp[c].Node;
tmp->Nodes++;
}
osFree(sorttemp);
return(TRUE);
}
bool AddSeenby(char *str,struct jbList *list)
{
/* Add a node string to SEEN-BY list */
uint32_t c,d;
char buf[60];
uint16_t lastnet,num;
c=0;
lastnet=0;
while(str[c]!=13 && str[c]!=0)
{
d=0;
while(str[c]!=0 && str[c]!=13 && str[c]!=32 && d<59)
buf[d++]=str[c++];
buf[d]=0;
while(str[c]==32) c++;
if(buf[0])
{
num=0;
d=0;
while(buf[d]>='0' && buf[d]<='9')
{
num*=10;
num+=buf[d]-'0';
d++;
}
if(buf[d]=='/')
{
lastnet=num;
num=atoi(&buf[d+1]);
if(!mmAddNodes2DList(list,lastnet,num))
return(FALSE);
}
else if(buf[d]==0)
{
if(!mmAddNodes2DList(list,lastnet,num))
return(FALSE);
}
}
}
return(TRUE);
}
void ProcessKludge(struct MemMessage *mm,char *kludge)
{
struct Node4D node;
char buf[60];
uint32_t c,d;
if(strncmp(kludge,"\x01RESCANNED",10)==0)
{
mm->Flags |= MMFLAG_RESCANNED;
}
if(strncmp(kludge,"\x01MSGID:",7)==0)
{
for(d=0,c=8;d<79 && kludge[c]!=13 && kludge[c]!=0;c++,d++)
mm->MSGID[d]=kludge[c];
mm->MSGID[d]=0;
}
if(strncmp(kludge,"\x01REPLY:",7)==0)
{
for(d=0,c=8;d<79 && kludge[c]!=13 && kludge[c]!=0;c++,d++)
mm->REPLY[d]=kludge[c];
mm->REPLY[d]=0;
}
if(mm->Area[0]==0)
{
if(strncmp(kludge,"\x01" "FMPT",5)==0)
mm->OrigNode.Point=atoi(&kludge[6]);
if(strncmp(kludge,"\x01TOPT",5)==0)
mm->DestNode.Point=atoi(&kludge[6]);
if(strncmp(kludge,"\x01INTL",5)==0)
{
if(kludge[5]==':')
c=7;
else
c=6;
for(d=0;d<59 && kludge[c]!=32 && kludge[c]!=0;c++,d++)
buf[d]=kludge[c];
buf[d]=0;
if(Parse4D(buf,&node))
{
mm->DestNode.Zone = node.Zone;
mm->DestNode.Net = node.Net;
mm->DestNode.Node = node.Node;
}
if(kludge[c]==32) c++;
for(d=0;d<59 && kludge[c]!=32 && kludge[c]!=0 && kludge[c]!=13;c++,d++)
buf[d]=kludge[c];
buf[d]=0;
if(Parse4D(buf,&node))
{
mm->OrigNode.Zone = node.Zone;
mm->OrigNode.Net = node.Net;
mm->OrigNode.Node = node.Node;
}
}
}
}
bool mmAddLine(struct MemMessage *mm,char *buf)
{
if(mm->Area[0] && strncmp(buf,"SEEN-BY:",8)==0)
return AddSeenby(&buf[9],&mm->SeenBy);
else if(mm->Area[0] && strncmp(buf,"\x01PATH:",6)==0)
return mmAddPath(&buf[7],&mm->Path);
else if(mm->Area[0] && strncmp(buf," * Origin: ",11)==0)
{
struct Node4D n4d;
if(ExtractAddress(buf,&n4d))
{
if(n4d.Zone == 0) n4d.Zone=mm->PktOrig.Zone;
Copy4D(&mm->Origin4D,&n4d);
}
}
else if(buf[0] == 1)
ProcessKludge(mm,buf);
return mmAddBuf(&mm->TextChunks,buf,(uint32_t)strlen(buf));
}
char *mmMakeSeenByBuf(struct jbList *list)
{
char *text;
uint32_t seenbys,size;
struct Nodes2D *nodes;
uint32_t c;
uint16_t lastnet;
char buf[100],buf2[50],buf3[20];
/* Count seenbys */
seenbys=0;
for(nodes=(struct Nodes2D *)list->First;nodes;nodes=nodes->Next)
seenbys+=nodes->Nodes;
/* We allocate generously. Maximum length per seenby: <space>12345/12345: 12 characters
79 characters - "SEEN-BY:" = 71 characters which makes 71/12 seenbys/line = 5
Fortunately even with this generous calculation will not result in huge memory
areas, 500 seenbys (which is a lot) would need 8000 bytes... */
size=(seenbys/5+1)*80;
/* Allocate our memory block */
if(!(text=osAlloc(size)))
return(NULL);
text[0]=0;
strcpy(buf,"SEEN-BY:");
lastnet=0;
for(nodes=(struct Nodes2D *)list->First;nodes;nodes=nodes->Next)
{
for(c=0;c<nodes->Nodes;c++)
{
if(nodes->Net[c]!=0 || nodes->Node[c]!=0)
{
strcpy(buf2," ");
if(nodes->Net[c]!=lastnet)
{
sprintf(buf3,"%u/",nodes->Net[c]);
strcat(buf2,buf3);
}
sprintf(buf3,"%u",nodes->Node[c]);
strcat(buf2,buf3);
lastnet=nodes->Net[c];
if(strlen(buf)+strlen(buf2) > 77)
{
strcat(text,buf);
strcat(text,"\x0d");
strcpy(buf,"SEEN-BY:");
sprintf(buf2," %u/%u",nodes->Net[c],nodes->Node[c]);
lastnet=nodes->Net[c];
strcat(buf,buf2);
}
else
{
strcat(buf,buf2);
}
}
}
}
if(strlen(buf)>8)
{
strcat(text,buf);
strcat(text,"\x0d");
}
return(text);
}

View File

@ -0,0 +1,83 @@
#ifndef MEMMESSAGE_H
#define MEMMESSAGE_H
#define PKT_CHUNKLEN 10000
#define PKT_NUM2D 50
#define PKT_NUMPATH 10
struct TextChunk
{
struct TextChunk *Next;
uint32_t Length;
char Data[PKT_CHUNKLEN];
};
struct Nodes2D
{
struct Nodes2D *Next;
uint16_t Nodes;
uint16_t Net[PKT_NUM2D];
uint16_t Node[PKT_NUM2D];
};
struct Path
{
struct Path *Next;
uint16_t Paths;
char Path[PKT_NUMPATH][100];
};
#define MMFLAG_RESCANNED 1
#define MMFLAG_EXPORTED 2
#define MMFLAG_TOSSED 4
#define MMFLAG_NOSECURITY 8
#define MMFLAG_AUTOGEN 16
#define MMFLAG_TWIT 32
#define MMFLAG_KILL 64
struct MemMessage
{
uint32_t msgnum;
struct Node4D OrigNode;
struct Node4D DestNode;
struct Node4D PktOrig;
struct Node4D PktDest;
struct Node4D Origin4D;
char Area[80];
char To[36];
char From[36];
char Subject[72];
char DateTime[20];
char MSGID[80];
char REPLY[80];
uint16_t Attr;
uint16_t Cost;
uint8_t Type;
uint16_t Flags;
struct jbList TextChunks;
struct jbList SeenBy;
struct jbList Path;
};
bool mmAddNodes2DList(struct jbList *list,uint16_t net,uint16_t node);
void mmRemNodes2DList(struct jbList *list,uint16_t net,uint16_t node);
void mmRemNodes2DListPat(struct jbList *list,struct Node2DPat *pat);
bool mmAddPath(char *str,struct jbList *list);
bool mmAddBuf(struct jbList *chunklist,char *buf,uint32_t len);
bool mmAddLine(struct MemMessage *mm,char *buf);
struct MemMessage *mmAlloc(void);
void mmClear(struct MemMessage *mm);
void mmFree(struct MemMessage *mm);
bool mmSortNodes2D(struct jbList *list);
char *mmMakeSeenByBuf(struct jbList *list);
#endif

View File

@ -0,0 +1,938 @@
#include "magimail.h"
void ExpandPacker(char *cmd,char *dest,uint32_t destsize,char *arc,char *file)
{
uint32_t c,d;
d=0;
for(c=0;c<strlen(cmd);c++)
{
if(cmd[c]=='%' && (cmd[c+1]|32)=='a')
{
strncpy(&dest[d],arc,(size_t)(destsize-1-d));
dest[destsize-1]=0;
d=strlen(dest);
c++;
}
else if(cmd[c]=='%' && (cmd[c+1]|32)=='f')
{
strncpy(&dest[d],file,(size_t)(destsize-1-d));
dest[destsize-1]=0;
d=strlen(dest);
c++;
}
else if(cmd[c]=='%' && cmd[c+1]!=0)
{
dest[d++]=cmd[c+1];
c++;
}
else dest[d++]=cmd[c];
}
dest[d]=0;
}
void ExpandFilter(char *cmd,char *dest,uint32_t destsize,
char *rfc1,
char *rfc2,
char *msg,
char *area,
char *subj,
char *date,
char *from,
char *to,
char *orignode,
char *destnode)
{
uint32_t c,d;
d=0;
for(c=0;c<strlen(cmd);c++)
{
if(cmd[c]=='%' && (cmd[c+1])=='a')
{
strncpy(&dest[d],area,(size_t)(destsize-1-d));
dest[destsize-1]=0;
d=strlen(dest);
c++;
}
else if(cmd[c]=='%' && (cmd[c+1])=='r')
{
strncpy(&dest[d],rfc1,(size_t)(destsize-1-d));
dest[destsize-1]=0;
d=strlen(dest);
c++;
}
else if(cmd[c]=='%' && (cmd[c+1])=='R')
{
strncpy(&dest[d],rfc2,(size_t)(destsize-1-d));
dest[destsize-1]=0;
d=strlen(dest);
c++;
}
else if(cmd[c]=='%' && (cmd[c+1]|32)=='m')
{
strncpy(&dest[d],msg,(size_t)(destsize-1-d));
dest[destsize-1]=0;
d=strlen(dest);
c++;
}
else if(cmd[c]=='%' && (cmd[c+1]|32)=='s')
{
strncpy(&dest[d],subj,(size_t)(destsize-1-d));
dest[destsize-1]=0;
d=strlen(dest);
c++;
}
else if(cmd[c]=='%' && (cmd[c+1]|32)=='x')
{
strncpy(&dest[d],date,(size_t)(destsize-1-d));
dest[destsize-1]=0;
d=strlen(dest);
c++;
}
else if(cmd[c]=='%' && (cmd[c+1]|32)=='f')
{
strncpy(&dest[d],from,(size_t)(destsize-1-d));
dest[destsize-1]=0;
d=strlen(dest);
c++;
}
else if(cmd[c]=='%' && (cmd[c+1]|32)=='t')
{
strncpy(&dest[d],to,(size_t)(destsize-1-d));
dest[destsize-1]=0;
d=strlen(dest);
c++;
}
else if(cmd[c]=='%' && (cmd[c+1]|32)=='o')
{
strncpy(&dest[d],orignode,(size_t)(destsize-1-d));
dest[destsize-1]=0;
d=strlen(dest);
c++;
}
else if(cmd[c]=='%' && (cmd[c+1]|32)=='d')
{
strncpy(&dest[d],destnode,(size_t)(destsize-1-d));
dest[destsize-1]=0;
d=strlen(dest);
c++;
}
else if(cmd[c]=='%' && cmd[c+1]!=0)
{
dest[d++]=cmd[c+1];
c++;
}
else dest[d++]=cmd[c];
}
dest[d]=0;
}
int DateCompareFE(const void *f1, const void *f2)
{
if((*(struct osFileEntry **)f1)->Date > (*(struct osFileEntry **)f2)->Date)
return(1);
if((*(struct osFileEntry **)f1)->Date < (*(struct osFileEntry **)f2)->Date)
return(-1);
return stricmp((*(struct osFileEntry **)f1)->Name,(*(struct osFileEntry **)f2)->Name);
/* Compares by filenames to get packet files with the same date in the right
order */
}
bool SortFEList(struct jbList *list)
{
struct osFileEntry *ftt,**buf,**work;
uint32_t nodecount = 0;
for(ftt=(struct osFileEntry *)list->First;ftt;ftt=ftt->Next)
nodecount++;
if(!nodecount)
return(TRUE);
if(!(buf=(struct osFileEntry **)osAlloc(nodecount * sizeof(struct osFileEntry *))))
{
nomem=TRUE;
return(FALSE);
}
work=buf;
for(ftt=(struct osFileEntry *)list->First;ftt;ftt=ftt->Next)
*work++=ftt;
qsort(buf,(size_t)nodecount,(size_t)sizeof(struct osFileEntry *),DateCompareFE);
jbNewList(list);
for(work=buf;nodecount--;)
jbAddNode(list,(struct jbNode *)*work++);
osFree(buf);
return(TRUE);
}
bool IsArc(char *file)
{
int c;
char ext[4];
if(strlen(file)!=12) return(FALSE);
if(file[8]!='.') return(FALSE);
for(c=0;c<8;c++)
if((file[c]<'0' || file[c]>'9') && ((tolower(file[c]) < 'a') || (tolower(file[c]) > 'f'))) return(FALSE);
strncpy(ext,&file[9],2);
ext[2]=0;
if(stricmp(ext,"MO")==0) return(TRUE);
if(stricmp(ext,"TU")==0) return(TRUE);
if(stricmp(ext,"WE")==0) return(TRUE);
if(stricmp(ext,"TH")==0) return(TRUE);
if(stricmp(ext,"FR")==0) return(TRUE);
if(stricmp(ext,"SA")==0) return(TRUE);
if(stricmp(ext,"SU")==0) return(TRUE);
return(FALSE);
}
bool IsPkt(char *file)
{
if(strlen(file)!=12) return(FALSE);
if(file[8]!='.') return(FALSE);
if(stricmp(&file[9],"pkt")!=0) return(FALSE);
return(TRUE);
}
bool IsNewPkt(char *file)
{
if(strlen(file) < 7)
return(FALSE);
if(stricmp(&file[strlen(file)-7],".newpkt")!=0)
return(FALSE);
return(TRUE);
}
bool IsPktTmp(char *file)
{
if(strlen(file) < 7)
return(FALSE);
if(stricmp(&file[strlen(file)-7],".pkttmp")!=0)
return(FALSE);
return(TRUE);
}
bool IsOrphan(char *file)
{
if(strlen(file) < 7)
return(FALSE);
if(stricmp(&file[strlen(file)-7],".orphan")!=0)
return(FALSE);
return(TRUE);
}
bool IsBad(char *file)
{
if(strlen(file)>4 && stricmp(&file[strlen(file)-4],".bad")==0)
return(TRUE);
return(FALSE);
}
void striptrail(char *str)
{
int c;
for(c=strlen(str)-1;str[c] < 33 && c>=0;c--)
str[c]=0;
}
void striplead(char *str)
{
int c;
char *tmp;
c=0;
while(str[c]==' ')
c++;
tmp = strdup(str);
strcpy(str,&tmp[c]);
free(tmp);
}
void stripleadtrail(char *str)
{
striplead(str);
striptrail(str);
}
void BadFile(char *filename,char *comment)
{
char destname[100],numbuf[10];
uint32_t num;
LogWrite(3,TOSSINGERR,"Renaming %s to .bad",filename);
num=0;
do
{
MakeFullPath(config.cfg_Inbound,GetFilePart(filename),destname,90);
strcat(destname,".bad");
if(num != 0)
{
sprintf(numbuf,",%d",num);
strcat(destname,numbuf);
}
num++;
} while(osExists(destname));
if(!movefile(filename,destname))
{
uint32_t err=osError();
LogWrite(1,SYSTEMERR,"Failed to move %s to %s",filename,destname);
LogWrite(1,SYSTEMERR,"Error: %s",osErrorMsg(err));
return;
}
osSetComment(destname,comment);
}
bool MatchFlags(char group,char *node)
{
uint8_t c;
for(c=0;c<strlen(node);c++)
{
if(group==node[c])
return(TRUE);
}
return(FALSE);
}
bool AddTID(struct MemMessage *mm)
{
char buf[100];
strcpy(buf,"\x01" "TID: MagiMail/" OS_PLATFORM_NAME " " TID_VERSION "\x0d");
return mmAddLine(mm,buf);
}
void MakeFidoDate(time_t tim,char *dest)
{
struct tm *tp;
time_t t;
char *monthnames[]={"Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec","???"};
t=tim;
tp=localtime(&t);
sprintf(dest,"%02d %s %02d %02d:%02d:%02d",
tp->tm_mday,
monthnames[tp->tm_mon],
tp->tm_year % 100,
tp->tm_hour,
tp->tm_min,
tp->tm_sec);
}
#define COPYBUFSIZE 5000
bool copyfile(char *file,char *newfile)
{
osFile ifh,ofh;
uint32_t len;
char *copybuf;
if(!(copybuf=(char *)malloc(COPYBUFSIZE)))
{
nomem=TRUE;
return(FALSE);
}
if(!(ifh=osOpen(file,MODE_OLDFILE)))
{
free(copybuf);
return(FALSE);
}
if(!(ofh=osOpen(newfile,MODE_NEWFILE)))
{
free(copybuf);
osClose(ifh);
return(FALSE);
}
while((len=osRead(ifh,copybuf,COPYBUFSIZE)) && !ioerror)
{
if(!osWrite(ofh,copybuf,len))
{ ioerror=TRUE; ioerrornum=osError(); }
}
free(copybuf);
osClose(ofh);
osClose(ifh);
if(ioerror)
{
osDelete(newfile);
return(FALSE);
}
return(TRUE);
}
bool movefile(char *file,char *newfile)
{
if(osRename(file,newfile))
return(TRUE); /* rename was enough */
if(!copyfile(file,newfile))
return(FALSE);
osDelete(file);
return(TRUE);
}
char ChangeType(struct Node4D *dest,char pri)
{
struct Change *change;
char newpri;
bool ispattern;
newpri=pri;
for(change=(struct Change *)config.ChangeList.First;change;change=change->Next)
{
if(Compare4DPat(&change->Pattern,dest)==0)
{
ispattern=FALSE;
if(pri == PKTS_ECHOMAIL && change->ChangeNormal == TRUE) ispattern=TRUE;
if(pri == PKTS_NORMAL && change->ChangeNormal == TRUE) ispattern=TRUE;
if(pri == PKTS_CRASH && change->ChangeCrash == TRUE) ispattern=TRUE;
if(pri == PKTS_DIRECT && change->ChangeDirect == TRUE) ispattern=TRUE;
if(pri == PKTS_HOLD && change->ChangeHold == TRUE) ispattern=TRUE;
if(ispattern)
{
if(pri == PKTS_ECHOMAIL && change->DestPri == PKTS_NORMAL)
newpri=pri;
else
newpri=change->DestPri;
}
}
}
return(newpri);
}
bool MakeNetmailKludges(struct MemMessage *mm)
{
char buf[100];
if(mm->OrigNode.Point)
{
sprintf(buf,"\x01" "FMPT %u\x0d",mm->OrigNode.Point);
mmAddBuf(&mm->TextChunks,buf,strlen(buf));
}
if(mm->DestNode.Point)
{
sprintf(buf,"\x01TOPT %u\x0d",mm->DestNode.Point);
mmAddBuf(&mm->TextChunks,buf,strlen(buf));
}
if(mm->OrigNode.Zone != mm->DestNode.Zone || (config.cfg_Flags & CFG_FORCEINTL))
{
sprintf(buf,"\x01INTL %u:%u/%u %u:%u/%u\x0d",
mm->DestNode.Zone,
mm->DestNode.Net,
mm->DestNode.Node,
mm->OrigNode.Zone,
mm->OrigNode.Net,
mm->OrigNode.Node);
mmAddBuf(&mm->TextChunks,buf,strlen(buf));
}
return(TRUE);
}
/*************************************/
/* */
/* Fido DateTime conversion routines */
/* */
/*************************************/
time_t FidoToTime(char *date)
{
uint32_t month;
struct tm tm;
time_t t;
static char *mo[12] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun",
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
if(date[2]==' ' && date[6]==' ')
{
/* Standard Fido "01 Jan 91 11:22:33" */
/* Get month */
for(month=0;month<12;month++)
if(strnicmp(mo[month],&date[3],3)==0) break;
if(month==12)
return time(NULL); /* return current time */
tm.tm_sec=atoi(&date[17]);
tm.tm_min=atoi(&date[14]);
tm.tm_hour=atoi(&date[11]);
tm.tm_mday=atoi(date);
tm.tm_mon=month;
tm.tm_year=atoi(&date[7]);
tm.tm_wday=0;
tm.tm_yday=0;
tm.tm_isdst=-1;
if(tm.tm_year < 80) /* Y2K fix */
tm.tm_year+=100;
}
else
{
/* SEAdog "Wed 13 Jan 86 02:34" */
/* SEAdog "Wed 3 Jan 86 02:34" */
/* Get month */
for(month=0;month<12;month++)
if(strnicmp(mo[month],&date[7],3)==0) break;
if(month==12)
return time(NULL); /* return current time */
tm.tm_sec=0;
tm.tm_min=atoi(&date[17]);
tm.tm_hour=atoi(&date[14]);
tm.tm_mday=atoi(&date[4]);
tm.tm_mon=month;
tm.tm_year=atoi(&date[11]);
tm.tm_wday=0;
tm.tm_yday=0;
tm.tm_isdst=-1;
if(tm.tm_year < 80) /* Y2K fix */
tm.tm_year+=100;
}
t=mktime(&tm);
if(t == -1)
t=time(NULL);
return(t);
}
bool Parse5D(char *buf, struct Node4D *n4d, char *domain)
{
uint32_t c=0;
char buf2[100];
domain[0]=0;
mystrncpy(buf2,buf,100);
for(c=0;c<strlen(buf2);c++)
if(buf2[c]=='@') break;
if(buf2[c]=='@')
{
buf2[c]=0;
mystrncpy(domain,&buf2[c+1],20);
}
return Parse4D(buf2,n4d);
}
bool ExtractAddress(char *origin, struct Node4D *n4d)
{
uint32_t pos,e;
char addr[50];
char domain[20];
pos=strlen(origin);
while(pos>0 && origin[pos]!='(') pos--;
/* Find address */
if(origin[pos]!='(')
return(FALSE);
pos++;
while(origin[pos]!=13 && (origin[pos]<'0' || origin[pos]>'9')) pos++;
/* Skip (FidoNet ... ) */
e=0;
while(origin[pos]!=')' && e<49)
addr[e++]=origin[pos++];
addr[e]=0;
return Parse5D(addr,n4d,domain);
}
unsigned long hextodec(char *hex)
{
char *hextab="0123456789abcdef";
int c=0,c2=0;
unsigned long result=0;
for(;;)
{
for(c2=0;c2<16;c2++)
if(tolower(hex[c]) == hextab[c2]) break;
if(c2 == 16)
return(result); /* End of correct hex number */
result *= 16;
result += c2;
c++;
}
}
/* WriteRFC and WriteMSG */
void MakeRFCAddr(char *dest,char *nam,struct Node4D *node,char *dom)
{
char domain[50],name[50];
int j;
/* Prepare domain */
strcpy(domain,dom);
for(j=0;domain[j];j++)
domain[j]=tolower(domain[j]);
if(stricmp(domain,"fidonet")==0)
strcpy(domain,"fidonet.org");
/* Prepare name */
strcpy(name,nam);
for(j=0;name[j];j++)
if(name[j] == ' ') name[j]='_';
/* Make addr */
if(node->Point != 0)
sprintf(dest,"%s@p%u.f%u.n%u.z%u.%s",
name,
node->Point,
node->Node,
node->Net,
node->Zone,
domain);
else
sprintf(dest,"%s@f%u.n%u.z%u.%s",
name,
node->Node,
node->Net,
node->Zone,
domain);
}
bool WriteRFC(struct MemMessage *mm,char *name,bool rfcaddr)
{
osFile fh;
char *domain;
struct Aka *aka;
struct TextChunk *tmp;
uint32_t c,d,lastspace;
char buffer[100],fromaddr[100],toaddr[100];
for(aka=(struct Aka *)config.AkaList.First;aka;aka=aka->Next)
if(Compare4D(&mm->DestNode,&aka->Node)==0) break;
domain="FidoNet";
if(aka && aka->Domain[0]!=0)
domain=aka->Domain;
if(rfcaddr)
{
MakeRFCAddr(fromaddr,mm->From,&mm->OrigNode,domain);
MakeRFCAddr(toaddr,mm->To,&mm->DestNode,domain);
}
else
{
sprintf(fromaddr,"%u:%u/%u.%u@%s",mm->OrigNode.Zone,
mm->OrigNode.Net,
mm->OrigNode.Node,
mm->OrigNode.Point,
domain);
sprintf(toaddr,"%u:%u/%u.%u@%s",mm->DestNode.Zone,
mm->DestNode.Net,
mm->DestNode.Node,
mm->DestNode.Point,
domain);
}
if(!(fh=osOpen(name,MODE_NEWFILE)))
{
uint32_t err=osError();
LogWrite(1,SYSTEMERR,"Unable to write RFC-message to %s",name);
LogWrite(1,SYSTEMERR,"Error: %s",osErrorMsg(err));
return(FALSE);
}
/* Write header */
if(!osFPrintf(fh,"From: %s (%s)\n",fromaddr,mm->From))
{ ioerror=TRUE; ioerrornum=osError(); }
if(!osFPrintf(fh,"To: %s (%s)\n",toaddr,mm->To))
{ ioerror=TRUE; ioerrornum=osError(); }
if(!osFPrintf(fh,"Subject: %s\n",mm->Subject))
{ ioerror=TRUE; ioerrornum=osError(); }
if(!osFPrintf(fh,"Date: %s\n",mm->DateTime))
{ ioerror=TRUE; ioerrornum=osError(); }
if(mm->MSGID[0]!=0)
{
if(!osFPrintf(fh,"Message-ID: <%s>\n",mm->MSGID))
{ ioerror=TRUE; ioerrornum=osError(); }
}
if(mm->REPLY[0]!=0)
{
if(!osFPrintf(fh,"References: <%s>\n",mm->REPLY))
{ ioerror=TRUE; ioerrornum=osError(); }
}
/* Write kludges */
for(tmp=(struct TextChunk *)mm->TextChunks.First;tmp;tmp=tmp->Next)
{
c=0;
while(c<tmp->Length)
{
for(d=c;d<tmp->Length && tmp->Data[d]!=13 && tmp->Data[d]!=10;d++);
if(tmp->Data[d]==13 || tmp->Data[d]==10) d++;
if(tmp->Data[c]==1 && d-c-2!=0)
{
if(!osPuts(fh,"X-Fido-"))
{ ioerror=TRUE; ioerrornum=osError(); }
if(!osWrite(fh,&tmp->Data[c+1],d-c-2))
{ ioerror=TRUE; ioerrornum=osError(); }
if(!osPuts(fh,"\n"))
{ ioerror=TRUE; ioerrornum=osError(); }
}
c=d;
}
}
/* Write end-of-header */
if(!osPuts(fh,"\n"))
{ ioerror=TRUE; ioerrornum=osError(); }
/* Write message text */
for(tmp=(struct TextChunk *)mm->TextChunks.First;tmp;tmp=tmp->Next)
{
d=0;
while(d<tmp->Length)
{
lastspace=0;
c=0;
while(tmp->Data[d+c]==10) d++;
while(c<78 && d+c<tmp->Length && tmp->Data[d+c]!=13)
{
if(tmp->Data[d+c]==32) lastspace=c;
c++;
}
if(c==78 && lastspace)
{
strncpy(buffer,&tmp->Data[d],lastspace);
buffer[lastspace]=0;
d+=lastspace+1;
}
else
{
strncpy(buffer,&tmp->Data[d],c);
buffer[c]=0;
if(tmp->Data[d+c]==13) c++;
d+=c;
}
if(buffer[0]!=1)
{
if(!osPuts(fh,buffer))
{ ioerror=TRUE; ioerrornum=osError(); }
if(!osPutChar(fh,'\n'))
{ ioerror=TRUE; ioerrornum=osError(); }
}
}
}
osClose(fh);
if(ioerror)
return(FALSE);
return(TRUE);
}
bool WriteMSG(struct MemMessage *mm,char *file)
{
struct StoredMsg Msg;
struct TextChunk *chunk;
struct Path *path;
osFile fh;
int c;
strcpy(Msg.From,mm->From);
strcpy(Msg.To,mm->To);
strcpy(Msg.Subject,mm->Subject);
strcpy(Msg.DateTime,mm->DateTime);
Msg.TimesRead=0;
Msg.ReplyTo=0;
Msg.NextReply=0;
Msg.Cost= mm->Cost;
Msg.Attr= mm->Attr | FLAG_SENT;
if(mm->Area[0]==0)
{
Msg.DestZone = mm->DestNode.Zone;
Msg.DestNet = mm->DestNode.Net;
Msg.DestNode = mm->DestNode.Node;
Msg.DestPoint = mm->DestNode.Point;
Msg.OrigZone = mm->OrigNode.Zone;
Msg.OrigNet = mm->OrigNode.Net;
Msg.OrigNode = mm->OrigNode.Node;
Msg.OrigPoint = mm->OrigNode.Point;
}
else
{
Msg.DestZone = 0;
Msg.DestNet = 0;
Msg.DestNode = 0;
Msg.DestPoint = 0;
Msg.OrigZone = 0;
Msg.OrigNet = 0;
Msg.OrigNode = 0;
Msg.OrigPoint = 0;
}
if(!(fh=osOpen(file,MODE_NEWFILE)))
{
uint32_t err=osError();
LogWrite(1,SYSTEMERR,"Unable to write message to %s",file);
LogWrite(1,SYSTEMERR,"Error: %s",osErrorMsg(err));
return(FALSE);
}
/* Write header */
if(!osWrite(fh,&Msg,sizeof(struct StoredMsg)))
{ ioerror=TRUE; ioerrornum=osError(); }
/* Write text */
for(chunk=(struct TextChunk *)mm->TextChunks.First;chunk;chunk=chunk->Next)
{
if(!osWrite(fh,chunk->Data,chunk->Length))
{ ioerror=TRUE; ioerrornum=osError(); }
}
/* Write seen-by */
if((config.cfg_Flags & CFG_IMPORTSEENBY) && mm->Area[0]!=0)
{
char *sbbuf;
if(!(sbbuf=mmMakeSeenByBuf(&mm->SeenBy)))
{
osClose(fh);
return(FALSE);
}
if(sbbuf[0])
{
if(!osWrite(fh,sbbuf,(uint32_t)strlen(sbbuf)))
{ ioerror=TRUE; ioerrornum=osError(); }
}
osFree(sbbuf);
}
/* Write path */
for(path=(struct Path *)mm->Path.First;path;path=path->Next)
for(c=0;c<path->Paths;c++)
if(path->Path[c][0]!=0)
{
if(!osWrite(fh,"\x01PATH: ",7))
{ ioerror=TRUE; ioerrornum=osError(); }
if(!osWrite(fh,path->Path[c],(uint32_t)strlen(path->Path[c])))
{ ioerror=TRUE; ioerrornum=osError(); }
if(!osWrite(fh,"\x0d",1))
{ ioerror=TRUE; ioerrornum=osError(); }
}
if(!osPutChar(fh,0))
{ ioerror=TRUE; ioerrornum=osError(); }
osClose(fh);
if(ioerror)
return(FALSE);
return(TRUE);
}

View File

@ -0,0 +1,53 @@
void ExpandPacker(char *cmd,char *dest,uint32_t destsize,char *archive,char *file);
bool SortFEList(struct jbList *list);
void BadFile(char *filename,char *comment);
bool IsArc(char *file);
bool IsPkt(char *file);
bool IsNewPkt(char *file);
bool IsPktTmp(char *file);
bool IsOrphan(char *file);
bool IsBad(char *file);
void striptrail(char *str);
void striplead(char *str);
void stripleadtrail(char *str);
bool MatchFlags(char group,char *node);
void ExpandFilter(char *cmd,char *dest,uint32_t destsize,
char *rfc1,
char *rfc2,
char *msg,
char *area,
char *subj,
char *time,
char *from,
char *to,
char *orignode,
char *destnode);
void MakeFidoDate(time_t tim,char *dest);
bool AddTID(struct MemMessage *mm);
bool movefile(char *file,char *newfile);
bool copyfile(char *file,char *newfile);
char ChangeType(struct Node4D *dest,char pri);
bool MakeNetmailKludges(struct MemMessage *mm);
time_t FidoToTime(char *date);
bool Parse5D(char *buf, struct Node4D *n4d, char *domain);
bool ExtractAddress(char *origin, struct Node4D *n4d);
unsigned long hextodec(char *hex);
bool WriteMSG(struct MemMessage *mm,char *file);
bool WriteRFC(struct MemMessage *mm,char *name,bool rfcaddr);

View File

@ -0,0 +1,39 @@
#include "magimail.h"
#ifdef NODELIST_CMNL
#include "nl_cmnl.h"
#endif
#ifdef NODELIST_V7P
#include "nl_v7p.h"
#endif
struct Nodelist AvailNodelists[] =
{
#ifdef NODELIST_CMNL
{ "CMNL",
"MagiMail nodelist index",
cmnl_nlStart,
cmnl_nlEnd,
cmnl_nlCheckNode,
cmnl_nlGetHub,
cmnl_nlGetRegion },
#endif
#ifdef NODELIST_V7P
{ "V7+",
"Version 7+ format",
v7p_nlStart,
v7p_nlEnd,
v7p_nlCheckNode,
v7p_nlGetHub,
v7p_nlGetRegion },
#endif
{ NULL, /* NULL here marks the end of the array */
NULL,
NULL,
NULL,
NULL,
NULL,
NULL }
};

View File

@ -0,0 +1,17 @@
#ifndef NL_H
#define NL_H
#include <shared/node4d.h>
struct Nodelist
{
char *name;
char *desc;
bool (*nlStart)(char *errbuf);
void (*nlEnd)(void);
bool (*nlCheckNode)(struct Node4D *node);
long (*nlGetHub)(struct Node4D *node);
long (*nlGetRegion)(struct Node4D *node);
};
#endif

View File

@ -0,0 +1,65 @@
#include "magimail.h"
#include "cmnllib/cmnllib.h"
osFile nlfh;
bool cmnl_nlStart(char *errbuf)
{
if(!(nlfh=cmnlOpenNL(config.cfg_Nodelist)))
{
strcpy(errbuf,cmnlLastError());
return(FALSE);
}
return(TRUE);
}
void cmnl_nlEnd(void)
{
cmnlCloseNL(nlfh);
}
bool cmnl_nlCheckNode(struct Node4D *node)
{
struct cmnlIdx idx;
idx.zone=node->Zone;
idx.net=node->Net;
idx.node=node->Node;
idx.point=node->Point;
if(!cmnlFindNL(nlfh,config.cfg_Nodelist,&idx,NULL,0))
return(FALSE);
return(TRUE);
}
long cmnl_nlGetHub(struct Node4D *node)
{
struct cmnlIdx idx;
idx.zone=node->Zone;
idx.net=node->Net;
idx.node=node->Node;
idx.point=node->Point;
if(!cmnlFindNL(nlfh,config.cfg_Nodelist,&idx,NULL,0))
return(-1);
return(idx.hub);
}
long cmnl_nlGetRegion(struct Node4D *node)
{
struct cmnlIdx idx;
idx.zone=node->Zone;
idx.net=node->Net;
idx.node=node->Node;
idx.point=node->Point;
if(!cmnlFindNL(nlfh,config.cfg_Nodelist,&idx,NULL,0))
return(-1);
return(idx.region);
}

View File

@ -0,0 +1,5 @@
bool cmnl_nlStart(char *errbuf);
void cmnl_nlEnd(void);
bool cmnl_nlCheckNode(struct Node4D *node);
long cmnl_nlGetHub(struct Node4D *node);
long cmnl_nlGetRegion(struct Node4D *node);

View File

@ -0,0 +1,437 @@
#include "magimail.h"
/* Data records for V7+ nodelist. As far as I can understand, these should
be stored on disk in native format. /JB */
#define V7P_NDXFILENAME "NODEX.ndx"
#define V7P_DATFILENAME "NODEX.dat"
#define V7P_DTPFILENAME "NODEX.dtp"
/* The Linux version of FastLst seems to use lower case for suffixes and
upper case for the rest */
#define V7P_NDXBUFSIZE 512
struct v7p_ndxcontrol
{
long indexstart;
long rootstart;
long lastblock;
long firstleaf;
long lastleaf;
long freelist;
uint16_t levels;
uint16_t xor;
};
struct v7p_ndxindex
{
long rectype;
long prev;
long next;
short keycount;
uint16_t keystart;
};
struct v7p_ndxindexkey
{
uint16_t offset;
uint16_t len;
long value;
long lower;
};
struct v7p_ndxleaf
{
long rectype;
long prev;
long next;
short keycount;
uint16_t keystart;
};
struct v7p_ndxleafkey
{
uint16_t offset;
uint16_t len;
long value;
};
struct v7p_datheader
{
short Zone,Net,Node,HubNode;
short CallCost,MsgFee,NodeFlags;
char ModemType;
char Phone_len;
char Password_len;
char Bname_len;
char Sname_len;
char Cname_len;
char pack_len;
char BaudRate;
};
osFile v7p_ndxfh;
osFile v7p_datfh;
osFile v7p_dtpfh;
uint16_t v7p_ndxrecsize;
struct v7p_ndxcontrol v7p_ndxcontrol;
struct v7p_datheader v7p_datheader;
char v7p_ndxbuf[V7P_NDXBUFSIZE];
int v7p_ndxcompare(char *d1,char *d2,int len)
{
struct Node4D n1,n2;
/* char b1[100],b2[100]; */
if(len != 8 && len != 6)
return(-1); /* Weird, but definitely not a match */
memcpy(&n1,d1,len);
memcpy(&n2,d2,sizeof(struct Node4D));
if(len == 6)
n1.Point=0;
/*
Print4D(&n1,b1);
Print4D(&n2,b2);
printf("compare %s and %s, %d\n",b1,b2,Compare4D(&n1,&n2));
*/
return Compare4D(&n1,&n2);
}
bool v7p_findoffset(struct Node4D *node,uint32_t *offset)
{
int i,res;
long recnum;
struct v7p_ndxindex *v7p_ndxindex;
struct v7p_ndxindexkey *v7p_ndxindexkey;
struct v7p_ndxleaf *v7p_ndxleaf;
struct v7p_ndxleafkey *v7p_ndxleafkey;
v7p_ndxindex=(struct v7p_ndxindex *)v7p_ndxbuf;
v7p_ndxleaf=(struct v7p_ndxleaf *)v7p_ndxbuf;
recnum=v7p_ndxcontrol.indexstart;
osSeek(v7p_ndxfh,recnum*v7p_ndxrecsize,OFFSET_BEGINNING);
if(osRead(v7p_ndxfh,v7p_ndxbuf,v7p_ndxrecsize) != v7p_ndxrecsize)
return(FALSE);
while(v7p_ndxindex->rectype != -1)
{
if(v7p_ndxindex->keycount < 0)
return(FALSE);
for(i=0;i < v7p_ndxindex->keycount;i++)
{
v7p_ndxindexkey=(struct v7p_ndxindexkey *)(v7p_ndxbuf+sizeof(struct v7p_ndxindex)+i*sizeof(struct v7p_ndxindexkey));
if(v7p_ndxcompare(v7p_ndxbuf+v7p_ndxindexkey->offset,(char *)node,v7p_ndxindexkey->len) > 0)
break;
}
if(i==0)
{
recnum=v7p_ndxindex->rectype;
}
else
{
v7p_ndxindexkey=(struct v7p_ndxindexkey *)(v7p_ndxbuf+sizeof(struct v7p_ndxindex)+(i-1)*sizeof(struct v7p_ndxindexkey));
recnum=v7p_ndxindexkey->lower;
}
osSeek(v7p_ndxfh,recnum*v7p_ndxrecsize,OFFSET_BEGINNING);
if(osRead(v7p_ndxfh,v7p_ndxbuf,v7p_ndxrecsize) != v7p_ndxrecsize)
return(FALSE);
}
if(v7p_ndxleaf->keycount <= 0)
return(FALSE);
for(i=0;i < v7p_ndxleaf->keycount;i++)
{
v7p_ndxleafkey=(struct v7p_ndxleafkey *)(v7p_ndxbuf+sizeof(struct v7p_ndxleaf)+i*sizeof(struct v7p_ndxleafkey));
res=v7p_ndxcompare(v7p_ndxbuf+v7p_ndxleafkey->offset,(char *)node,v7p_ndxleafkey->len);
if(res > 0)
{
return(FALSE);
}
else if(res == 0)
{
*offset=v7p_ndxleafkey->value;
break;
}
}
if(i == v7p_ndxleaf->keycount)
return(FALSE);
return(TRUE);
}
uint32_t v7p_unpack(char *dest,char *pack,uint32_t size)
{
uint32_t c,d;
uint16_t w;
char *table=" EANROSTILCHBDMUGPKYWFVJXZQ-'0123456789";
d=0;
for(c=0;c<size;c+=2)
{
w=pack[c]+pack[c+1]*256;
dest[d+2]=table[w % 40];
w/=40;
dest[d+1]=table[w % 40];
w/=40;
dest[d]=table[w % 40];
w/=40;
d+=3;
}
return(d);
}
bool v7p_gethubregion(uint32_t datoffset,uint32_t *hub,uint32_t *region)
{
uint32_t dtpoffset,sum;
char *junk,*unpacked;
int sz,d,c;
osSeek(v7p_datfh,datoffset,OFFSET_BEGINNING);
if(osRead(v7p_datfh,&v7p_datheader,sizeof(struct v7p_datheader)) != sizeof(struct v7p_datheader))
return(FALSE);
sz=v7p_datheader.Phone_len;
if(v7p_datheader.Password_len > sz)
sz=v7p_datheader.Password_len;
if(v7p_datheader.pack_len > sz)
sz=v7p_datheader.pack_len;
if(!(junk=osAlloc(sz)))
{
return(FALSE);
}
if(!(unpacked=osAlloc(sz*3/2+3)))
{
osFree(junk);
return(FALSE);
}
if(osRead(v7p_datfh,junk,v7p_datheader.Phone_len) != v7p_datheader.Phone_len)
{
osFree(junk);
osFree(unpacked);
return(FALSE);
}
if(osRead(v7p_datfh,junk,v7p_datheader.Password_len) != v7p_datheader.Password_len)
{
osFree(junk);
osFree(unpacked);
return(FALSE);
}
if(osRead(v7p_datfh,junk,v7p_datheader.pack_len) != v7p_datheader.pack_len)
{
osFree(junk);
osFree(unpacked);
return(FALSE);
}
d=v7p_unpack(unpacked,junk,v7p_datheader.pack_len);
unpacked[d]=0;
sum = v7p_datheader.Bname_len + v7p_datheader.Sname_len + v7p_datheader.Cname_len;
if(d-sum < 8)
{
/* not v7+ */
osFree(junk);
osFree(unpacked);
return(FALSE);
}
for(c=0;c<8;c++)
if(!isxdigit(unpacked[sum+c]))
{
/* not v7+ */
osFree(junk);
osFree(unpacked);
return(FALSE);
}
unpacked[sum+8]=0;
dtpoffset=hextodec(&unpacked[sum]);
osSeek(v7p_dtpfh,dtpoffset,OFFSET_BEGINNING);
if(osRead(v7p_dtpfh,junk,4) != 4)
{
osFree(junk);
osFree(unpacked);
return(FALSE);
}
*region = junk[0]+junk[1]*256; /* Platform-independent */
*hub = junk[2]+junk[3]*256;
osFree(junk);
osFree(unpacked);
return(TRUE);
}
bool v7p_nlStart(char *errbuf)
{
char ndxname[120],datname[120],dtpname[120];
MakeFullPath(config.cfg_Nodelist,V7P_NDXFILENAME,ndxname,120);
MakeFullPath(config.cfg_Nodelist,V7P_DATFILENAME,datname,120);
MakeFullPath(config.cfg_Nodelist,V7P_DTPFILENAME,dtpname,120);
if(!(v7p_ndxfh=osOpen(ndxname,MODE_OLDFILE)))
{
sprintf(errbuf,"Failed to open V7+ index file \"%s\"",ndxname);
return(FALSE);
}
if(!(v7p_datfh=osOpen(datname,MODE_OLDFILE)))
{
sprintf(errbuf,"Failed to open V7+ data file \"%s\"",datname);
osClose(v7p_ndxfh);
return(FALSE);
}
if(!(v7p_dtpfh=osOpen(dtpname,MODE_OLDFILE)))
{
sprintf(errbuf,"Failed to open V7+ dtp file \"%s\" (not a V7+ nodelist?)",dtpname);
osClose(v7p_ndxfh);
osClose(v7p_datfh);
return(FALSE);
}
if(osRead(v7p_ndxfh,&v7p_ndxrecsize,sizeof(uint16_t))!=sizeof(uint16_t))
{
sprintf(errbuf,"V7+ nodelist \"%s\" appears to be corrupt",config.cfg_Nodelist);
osClose(v7p_ndxfh);
osClose(v7p_datfh);
osClose(v7p_dtpfh);
return(FALSE);
}
if(v7p_ndxrecsize > V7P_NDXBUFSIZE)
{
sprintf(errbuf,"Record size of V7+ nodelist is too big (%d chars, max is %d chars)",v7p_ndxrecsize,V7P_NDXBUFSIZE);
osClose(v7p_ndxfh);
osClose(v7p_datfh);
osClose(v7p_dtpfh);
return(FALSE);
}
if(osRead(v7p_ndxfh,&v7p_ndxcontrol,sizeof(struct v7p_ndxcontrol))!=sizeof(struct v7p_ndxcontrol))
{
sprintf(errbuf,"V7+ nodelist \"%s\" appears to be corrupt",config.cfg_Nodelist);
osClose(v7p_ndxfh);
osClose(v7p_datfh);
osClose(v7p_dtpfh);
return(FALSE);
}
return(TRUE);
}
void v7p_nlEnd(void)
{
osClose(v7p_ndxfh);
osClose(v7p_datfh);
osClose(v7p_dtpfh);
}
bool v7p_nlCheckNode(struct Node4D *node)
{
uint32_t junk;
if(v7p_findoffset(node,&junk))
return(TRUE);
return(FALSE);
}
long v7p_nlGetHub(struct Node4D *node)
{
struct Node4D t4d;
uint32_t hub,region,datoffset;
Copy4D(&t4d,node);
t4d.Point=0;
if(!v7p_findoffset(&t4d,&datoffset))
return(-1);
if(!v7p_gethubregion(datoffset,&hub,&region))
return(-1);
return(hub);
}
long v7p_nlGetRegion(struct Node4D *node)
{
struct Node4D t4d;
uint32_t hub,region,datoffset;
Copy4D(&t4d,node);
t4d.Point=0;
if(!v7p_findoffset(&t4d,&datoffset))
return(-1);
if(!v7p_gethubregion(datoffset,&hub,&region))
return(-1);
return(region);
}
/* for testing
int main(int argc, char **argv)
{
char err[200];
struct Node4D n;
nlname=argv[1];
if(!v7p_nlStart(err))
{
printf("err: %s\n",err);
exit(10);
}
Parse4D(argv[2],&n);
printf(" check: %d\n",v7p_nlCheckNode(&n));
printf(" hub: %d\n",v7p_nlGetHub(&n));
printf("region: %d\n",v7p_nlGetRegion(&n));
v7p_nlEnd();
exit(0);
}
*/

View File

@ -0,0 +1,5 @@
bool v7p_nlStart(char *errbuf);
void v7p_nlEnd(void);
bool v7p_nlCheckNode(struct Node4D *node);
long v7p_nlGetHub(struct Node4D *node);
long v7p_nlGetRegion(struct Node4D *node);

View File

@ -0,0 +1,999 @@
#include "magimail.h"
struct jbList ArcList;
bool doAddFlow(char *filename,char *basename,char type,long mode);
bool LockBasename(char *basename)
{
char buf[200];
osFile fp;
strcpy(buf,basename);
strcat(buf,".bsy");
if(osExists(buf))
return(FALSE);
if(!(fp=osOpen(buf,MODE_NEWFILE)))
{
uint32_t err=osError();
LogWrite(1,SYSTEMERR,"Failed to create busy file %s\n",buf);
LogWrite(1,SYSTEMERR,"Error: %s",osErrorMsg(err));
return(FALSE);
}
osClose(fp);
return(TRUE);
}
void UnlockBasename(char *basename)
{
char buf[200];
strcpy(buf,basename);
strcat(buf,".bsy");
osDelete(buf);
}
void MakeBaseName(struct Node4D *n4d,char *basename)
{
struct Aka *firstaka;
struct Route *tmproute;
bool samedomain;
char *ospathchars;
uint32_t num,c;
char buf[50];
ospathchars=OS_PATH_CHARS;
for(tmproute=(struct Route *)config.RouteList.First;tmproute;tmproute=tmproute->Next)
if(Compare4DPat(&tmproute->Pattern,n4d)==0) break;
firstaka=(struct Aka *)config.AkaList.First;
samedomain=FALSE;
if(!tmproute)
samedomain=TRUE;
else if(tmproute->Aka->Domain[0]==0 || firstaka->Domain[0]==0 || stricmp(tmproute->Aka->Domain,firstaka->Domain)==0)
samedomain=TRUE;
if(samedomain)
{
/* Main domain */
strcpy(basename,config.cfg_Outbound);
if(basename[0])
{
if(strchr(ospathchars,basename[strlen(basename)-1]))
basename[strlen(basename)-1]=0; /* Strip / */
}
if(n4d->Zone != firstaka->Node.Zone)
{
/* Not in main zone */
num=n4d->Zone;
if(!(config.cfg_Flags & CFG_NOMAXOUTBOUNDZONE))
{
if(num > 0xfff)
num=0xfff;
}
sprintf(buf,".%03x",num);
strcat(basename,buf);
}
}
else
{
/* Other domain */
strcpy(basename,config.cfg_Outbound);
if(basename[0])
{
if(strchr(ospathchars,basename[strlen(basename)-1]))
basename[strlen(basename)-1]=0; /* Strip / */
}
*GetFilePart(basename)=0; /* Use domain as last component in path */
strcat(basename,tmproute->Aka->Domain);
num=n4d->Zone;
if(!(config.cfg_Flags & CFG_NOMAXOUTBOUNDZONE))
{
if(num > 0xfff)
num=0xfff;
}
sprintf(buf,".%03x",num);
strcat(basename,buf);
}
if(!osExists(basename))
osMkDir(basename);
/* Add slash */
c=strlen(basename);
basename[c++]=ospathchars[0];
basename[c++]=0;
/* Add net/node */
sprintf(buf,"%04x%04x",n4d->Net,n4d->Node);
strcat(basename,buf);
if(n4d->Point)
{
strcat(basename,".pnt");
if(!osExists(basename))
osMkDir(basename);
/* Add slash */
c=strlen(basename);
basename[c++]=ospathchars[0];
basename[c++]=0;
/* Add point */
sprintf(buf,"%08x",n4d->Point);
strcat(basename,buf);
}
}
void WriteIndex(void)
{
osFile fh;
char buf[200];
struct ConfigNode *cnode;
MakeFullPath(config.cfg_PacketDir,"cmindex",buf,200);
/* Get basenum */
if(!(fh=osOpen(buf,MODE_NEWFILE)))
return;
for(cnode=(struct ConfigNode *)config.CNodeList.First;cnode;cnode=cnode->Next)
if(cnode->LastArcName[0])
{
Print4D(&cnode->Node,buf);
osFPrintf(fh,"%s %s\n",buf,cnode->LastArcName);
}
osClose(fh);
}
void ReadIndex(void)
{
osFile fh;
char buf[200],buf2[200];
uint32_t jbcpos;
struct ConfigNode *cnode,*c1,*c2;
struct Node4D n4d;
MakeFullPath(config.cfg_PacketDir,"cmindex",buf,200);
/* Get basenum */
if(!(fh=osOpen(buf,MODE_OLDFILE)))
return;
while(osFGets(fh,buf,200))
{
striptrail(buf);
jbcpos=0;
jbstrcpy(buf2,buf,200,&jbcpos);
if(Parse4D(buf2,&n4d))
{
jbstrcpy(buf2,buf,200,&jbcpos);
for(cnode=(struct ConfigNode *)config.CNodeList.First;cnode;cnode=cnode->Next)
if(Compare4D(&cnode->Node,&n4d)==0) mystrncpy(cnode->LastArcName,buf2,13);
}
}
osClose(fh);
/* Check for duplicates */
for(c1=(struct ConfigNode *)config.CNodeList.First;c1;c1=c1->Next)
for(c2=c1->Next;c2;c2=c2->Next)
if(c1->LastArcName[0] && hextodec(c1->LastArcName) == hextodec(c2->LastArcName))
{
LogWrite(1,TOSSINGINFO,"Warning: The same bundle name is used for %u:%u/%u.%u and %u:%u/%u.%u",
c1->Node.Zone,
c1->Node.Net,
c1->Node.Node,
c1->Node.Point,
c2->Node.Zone,
c2->Node.Net,
c2->Node.Node,
c2->Node.Point);
LogWrite(1,TOSSINGINFO,"Cleared bundle name for %u:%u/%u.%u",
c2->Node.Zone,
c2->Node.Net,
c2->Node.Node,
c2->Node.Point);
c2->LastArcName[0]=0;
WriteIndex();
}
}
bool ExistsBasenum(uint32_t num)
{
char name[20];
struct osFileEntry *fe;
struct ConfigNode *cnode;
sprintf(name,"%08x.",num);
for(fe=(struct osFileEntry *)ArcList.First;fe;fe=fe->Next)
if(IsArc(fe->Name) && hextodec(fe->Name) == num) return(TRUE);
for(cnode=(struct ConfigNode *)config.CNodeList.First;cnode;cnode=cnode->Next)
if(cnode->LastArcName[0] && hextodec(cnode->LastArcName) == num) return(TRUE);
return(FALSE);
}
bool ExistsBundle(uint32_t basenum,uint32_t num)
{
char name[20];
struct osFileEntry *fe;
char *daynames[]={"su","mo","tu","we","th","fr","sa"};
sprintf(name,"%08x.%s%d",basenum,daynames[num/10],num%10);
for(fe=(struct osFileEntry *)ArcList.First;fe;fe=fe->Next)
if(stricmp(fe->Name,name)==0) return(TRUE);
return(FALSE);
}
void MakeArcName(struct ConfigNode *cnode,char *dest)
{
struct osFileEntry *fe,*foundfe;
char ext[10];
uint32_t basenum;
uint32_t suffix,newsuffix,day,i;
char *daynames[]={"su","mo","tu","we","th","fr","sa"};
time_t t;
struct tm *tp;
time(&t);
tp=localtime(&t);
day=tp->tm_wday;
/* Get basenum and suffix of latest bundle */
suffix=-1;
if(!cnode->LastArcName[0])
{
basenum=time(NULL);
while(ExistsBasenum(basenum))
basenum++;
}
else
{
basenum=hextodec(cnode->LastArcName);
strncpy(ext,&cnode->LastArcName[strlen(cnode->LastArcName)-3],3);
ext[2]=0;
for(i=0;i<7;i++)
{
if(stricmp(ext,daynames[i])==0)
{
suffix=i*10;
suffix+=cnode->LastArcName[strlen(cnode->LastArcName)-1]-'0';
}
}
}
/* Does LastArcName still exist in directory? */
foundfe=NULL;
if(cnode->LastArcName[0])
{
for(fe=(struct osFileEntry *)ArcList.First;fe;fe=fe->Next)
if(stricmp(cnode->LastArcName,fe->Name)==0) foundfe=fe;
}
if(suffix == -1)
{
if((config.cfg_Flags & CFG_WEEKDAYNAMING))
newsuffix=day*10;
else
newsuffix=0;
}
else
{
newsuffix=suffix;
if(!foundfe)
{
newsuffix=-1;
}
else
{
if(foundfe->Size == 0)
newsuffix=-1;
if(foundfe->Size > config.cfg_MaxBundleSize)
newsuffix=-1;
}
if((config.cfg_Flags & CFG_WEEKDAYNAMING) && suffix/10 != day)
newsuffix=-1;
if(newsuffix == -1)
{
newsuffix=suffix+1;
if(newsuffix == 70) newsuffix=0;
if((config.cfg_Flags & CFG_WEEKDAYNAMING) && newsuffix/10 != day)
newsuffix=day*10;
if(ExistsBundle(basenum,newsuffix))
newsuffix=suffix;
}
}
sprintf(dest,"%08x.%s%d",basenum,daynames[newsuffix/10],newsuffix%10);
if(stricmp(cnode->LastArcName,dest)!=0)
{
mystrncpy(cnode->LastArcName,dest,13);
WriteIndex();
}
}
void DeleteZero(char *dir,struct jbList *arclist)
{
struct osFileEntry *fe,*fe2;
char buf[200];
/* Delete zero length bundles for this node */
fe=(struct osFileEntry *)arclist->First;
while(fe)
{
fe2=fe->Next;
if(fe->Size == 0)
{
MakeFullPath(dir,fe->Name,buf,200);
LogWrite(2,TOSSINGINFO,"Deleting zero length bundle %s",buf);
osDelete(buf);
jbFreeNode(&ArcList,(struct jbNode *)fe);
}
fe=fe2;
}
}
void HandleOrphan(char *name)
{
osFile fh;
char buf[200],buf2[200];
char type;
bool mode;
uint32_t jbcpos;
struct Node4D n4d;
char basename[200];
if(!(fh=osOpen(name,MODE_OLDFILE)))
{
uint32_t err=osError();
LogWrite(1,SYSTEMERR,"Failed to open orphan file \"%s\"",name);
LogWrite(1,SYSTEMERR,"Error: %s",osErrorMsg(err));
return;
}
if(!osFGets(fh,buf,100))
{
LogWrite(1,SYSTEMERR,"Orphan file \"%s\" contains no information",name);
osClose(fh);
return;
}
osClose(fh);
jbcpos=0;
jbstrcpy(buf2,buf,100,&jbcpos);
if(stricmp(buf2,"Normal")==0)
type=PKTS_NORMAL;
else if(stricmp(buf2,"Hold")==0)
type=PKTS_HOLD;
else if(stricmp(buf2,"Direct")==0)
type=PKTS_DIRECT;
else if(stricmp(buf2,"Crash")==0)
type=PKTS_CRASH;
else
{
LogWrite(1,SYSTEMERR,"Unknown flavour \"%s\" in \"%s\"",buf2,name);
return;
}
jbstrcpy(buf2,buf,100,&jbcpos);
if(!Parse4D(buf2,&n4d))
{
LogWrite(1,SYSTEMERR,"Invalid node \"%s\" in \"%s\"",buf2,name);
return;
}
mode=FLOW_NONE;
jbstrcpy(buf2,buf,100,&jbcpos);
if(stricmp(buf2,"Truncate")==0)
mode=FLOW_TRUNC;
if(stricmp(buf2,"Delete")==0)
mode=FLOW_DELETE;
mystrncpy(buf,name,200);
buf[strlen(buf)-7]=0; /* Remove .orphan */
MakeBaseName(&n4d,basename);
if(!LockBasename(basename))
{
printf("Cannot add to %s, node is busy...\n",GetFilePart(basename));
return;
}
if(doAddFlow(buf,basename,type,mode))
osDelete(name); /* Orphan file no longer needed */
UnlockBasename(basename);
}
void MakeOrphan(char *file,struct Node4D *n4d,char type,long mode)
{
char buf[200];
osFile fh;
strcpy(buf,file);
strcat(buf,".orphan");
if(!(fh=osOpen(buf,MODE_NEWFILE)))
{
uint32_t err=osError();
LogWrite(1,SYSTEMERR,"Failed to open \"%s\", cannot make .orphan file",buf);
LogWrite(1,SYSTEMERR,"Error: %s",osErrorMsg(err));
return;
}
sprintf(buf,"%s %d:%d/%d.%d",prinames[(int)type],n4d->Zone,n4d->Net,n4d->Node,n4d->Point);
if(mode==FLOW_TRUNC) strcat(buf," Truncate");
else if(mode==FLOW_DELETE) strcat(buf," Delete");
strcat(buf,"\n");
osPuts(fh,buf);
osClose(fh);
}
/* Only call if file is already locked */
/* MakeOrphan() should be called if necessary */
bool doAddFlow(char *filename,char *basename,char type,long mode)
{
char buf[200],letter,*prefix;
osFile fh;
char *buff2;
switch(type)
{
case PKTS_NORMAL:
case PKTS_ECHOMAIL: letter='f';
break;
case PKTS_HOLD: letter='h';
break;
case PKTS_DIRECT: letter='d';
break;
case PKTS_CRASH: letter='c';
break;
default: letter='f';
}
sprintf(buf,"%s.%clo",basename,letter);
if(!(fh=osOpen(buf,MODE_READWRITE)))
{
uint32_t err=osError();
LogWrite(1,SYSTEMERR,"Failed to open \"%s\"",buf);
LogWrite(1,SYSTEMERR,"Error: %s",osErrorMsg(err));
return(FALSE);
}
while(osFGets(fh,buf,200))
{
striptrail(buf);
buff2 = buf;
if(buf[0]=='#') buff2 = &buf[1];
if(buf[0]=='~') buff2 = &buf[1];
if(buf[0]=='^') buff2 = &buf[1];
if(buf[0]=='-') buff2 = &buf[1];
if(stricmp(buff2,filename)==0)
{
osClose(fh);
return(TRUE); /* Was already in flow file */
}
}
osSeek(fh,0,OFFSET_END);
prefix="";
if(mode == FLOW_TRUNC)
prefix="#";
if(mode == FLOW_DELETE)
prefix="^";
if(config.cfg_Flags & CFG_FLOWCRLF) osFPrintf(fh,"%s%s\r\n",prefix,filename);
else osFPrintf(fh,"%s%s\n",prefix,filename);
osClose(fh);
return(TRUE);
}
/* Handles locking and MakeOrphan() */
bool AddFlow(char *filename,struct Node4D *n4d,char type,long mode)
{
char basename[200];
MakeBaseName(n4d,basename);
if(!LockBasename(basename))
{
printf("Cannot add to %s, node is busy...\n",GetFilePart(basename));
MakeOrphan(filename,n4d,type,mode);
return(FALSE);
}
if(!doAddFlow(filename,basename,type,mode))
MakeOrphan(filename,n4d,type,mode);
UnlockBasename(basename);
return(TRUE);
}
bool MakePktTmp(char *name)
{
char buf[200];
MakeFullPath(config.cfg_PacketDir,GetFilePart(name),buf,200);
strcpy(&buf[strlen(buf)-6],"pkttmp"); /* Change suffix */
if(!movefile(name,buf))
{
LogWrite(1,SYSTEMERR,"Failed to move file \"%s\" to \"%s\"",name,buf);
return(FALSE);
}
return(TRUE);
}
void UpdateFile(char *name)
{
struct osFileEntry *newfe,*fe;
if(!(newfe=osGetFileEntry(name)))
return;
for(fe=(struct osFileEntry *)ArcList.First;fe;fe=fe->Next)
if(stricmp(fe->Name,name)==0) break;
if(fe)
{
fe->Date=newfe->Date;
fe->Size=newfe->Size;
osFree(newfe);
}
else
{
jbAddNode(&ArcList,(struct jbNode *)newfe);
}
}
#define COPYBUFSIZE 5000
bool PackFile(char *file)
{
char basename[200],arcname[200],pktname[200],buf[200],buf2[200],*copybuf;
uint32_t jbcpos,readlen;
int c,res;
struct Node4D n4d;
char type;
char letter;
osFile ifh,ofh;
/* Parse filename */
mystrncpy(buf,GetFilePart(file),200);
for(c=0;buf[c];c++)
if(buf[c]=='_') buf[c]=' ';
jbcpos=0;
jbstrcpy(buf2,buf,100,&jbcpos);
jbstrcpy(buf2,buf,100,&jbcpos);
if(stricmp(buf2,"Normal")==0)
type=PKTS_NORMAL;
else if(stricmp(buf2,"Hold")==0)
type=PKTS_HOLD;
else if(stricmp(buf2,"Direct")==0)
type=PKTS_DIRECT;
else if(stricmp(buf2,"Crash")==0)
type=PKTS_CRASH;
else if(stricmp(buf2,"Echomail")==0)
type=PKTS_ECHOMAIL;
else
{
LogWrite(1,TOSSINGERR,"Unknown flavour \"%s\" for \"%s\"",buf2,file);
return(FALSE);
}
jbstrcpy(buf2,buf,100,&jbcpos);
n4d.Zone=atol(buf2);
jbstrcpy(buf2,buf,100,&jbcpos);
n4d.Net=atol(buf2);
jbstrcpy(buf2,buf,100,&jbcpos);
n4d.Node=atol(buf2);
jbstrcpy(buf2,buf,100,&jbcpos);
n4d.Point=atol(buf2);
/* Make basename for this node */
MakeBaseName(&n4d,basename);
if(!LockBasename(basename))
{
LogWrite(1,TOSSINGINFO,"Cannot add \"%s\" to outbound, node is busy...",GetFilePart(file));
return(FALSE);
}
/* Handle echomail packet */
if(type == PKTS_ECHOMAIL)
{
struct ConfigNode *cnode;
for(cnode=(struct ConfigNode *)config.CNodeList.First;cnode;cnode=cnode->Next)
if(Compare4D(&cnode->Node,&n4d)==0) break;
if(cnode && cnode->Packer)
{
/* Pack echomail */
MakeArcName(cnode,buf);
MakeFullPath(config.cfg_PacketDir,buf,arcname,200);
mystrncpy(pktname,file,200);
GetFilePart(pktname)[8]=0;
strcat(pktname,".pkt");
LogWrite(4,TOSSINGINFO,"Packing %s for %d:%d/%d.%d with %s",
GetFilePart(pktname),
cnode->Node.Zone,
cnode->Node.Net,
cnode->Node.Node,
cnode->Node.Point,
cnode->Packer->Name);
osRename(file,pktname);
if(config.cfg_BeforePack[0])
{
ExpandPacker(config.cfg_BeforePack,buf,200,arcname,pktname);
res=osExecute(buf);
if(res != 0)
{
osRename(pktname,file);
LogWrite(1,SYSTEMERR,"BEFOREPACK command failed: %u",res);
UnlockBasename(basename);
return(FALSE);
}
}
ExpandPacker(cnode->Packer->Packer,buf,200,arcname,pktname);
res=osExecute(buf);
if(res == 0)
{
UpdateFile(arcname);
osDelete(pktname);
if(!doAddFlow(arcname,basename,cnode->EchomailPri,FLOW_DELETE))
MakeOrphan(arcname,&n4d,cnode->EchomailPri,FLOW_DELETE);
}
else
{
osRename(pktname,file);
LogWrite(1,SYSTEMERR,"Packer failed: %u",res);
UnlockBasename(basename);
return(FALSE);
}
}
else
{
/* Send unpacked echomail */
MakeFullPath(config.cfg_PacketDir,GetFilePart(file),pktname,200);
GetFilePart(pktname)[8]=0;
strcat(pktname,".pkt");
LogWrite(4,TOSSINGINFO,"Sending %s unpacked to %d:%d/%d.%d",
GetFilePart(pktname),
cnode->Node.Zone,
cnode->Node.Net,
cnode->Node.Node,
cnode->Node.Point);
if(!movefile(file,pktname))
{
LogWrite(1,SYSTEMERR,"Failed to move file \"%s\" to \"%s\"",file,pktname);
UnlockBasename(basename);
return(FALSE);
}
else
{
if(!doAddFlow(pktname,basename,cnode->EchomailPri,FLOW_DELETE))
MakeOrphan(pktname,&n4d,cnode->EchomailPri,FLOW_DELETE);
}
}
}
else
{
/* Netmail */
switch(type)
{
case PKTS_NORMAL:
case PKTS_ECHOMAIL: letter='o';
break;
case PKTS_HOLD: letter='h';
break;
case PKTS_DIRECT: letter='d';
break;
case PKTS_CRASH: letter='c';
break;
default: letter='f';
}
sprintf(buf2,".%cut",letter);
strcpy(buf,basename);
strcat(buf,buf2);
LogWrite(4,TOSSINGINFO,"Sending unpacked netmail to %d:%d/%d.%d (%s)",
n4d.Zone,
n4d.Net,
n4d.Node,
n4d.Point,
prinames[(int)type]);
if(!(copybuf=(char *)osAlloc(COPYBUFSIZE)))
{
nomem=TRUE;
UnlockBasename(basename);
return(FALSE);
}
if(!(ifh=osOpen(file,MODE_OLDFILE)))
{
uint32_t err=osError();
LogWrite(1,SYSTEMERR,"Failed to open \"%s\"",file);
LogWrite(1,SYSTEMERR,"Error: %s",osErrorMsg(err));
osFree(copybuf);
UnlockBasename(basename);
return(FALSE);
}
if(osExists(buf))
{
if(!(ofh=osOpen(buf,MODE_READWRITE)))
{
uint32_t err=osError();
LogWrite(1,SYSTEMERR,"Failed to open \"%s\"",file);
LogWrite(1,SYSTEMERR,"Error: %s",osErrorMsg(err));
osClose(ifh);
osFree(copybuf);
UnlockBasename(basename);
return(FALSE);
}
osSeek(ifh,SIZE_PKTHEADER,OFFSET_BEGINNING);
osSeek(ofh,-2,OFFSET_END);
}
else
{
if(!(ofh=osOpen(buf,MODE_NEWFILE)))
{
uint32_t err=osError();
LogWrite(1,SYSTEMERR,"Failed to open \"%s\"",file);
LogWrite(1,SYSTEMERR,"Error: %s",osErrorMsg(err));
osClose(ifh);
osFree(copybuf);
UnlockBasename(basename);
return(FALSE);
}
}
while((readlen=osRead(ifh,copybuf,COPYBUFSIZE)))
{
if(!osWrite(ofh,copybuf,readlen))
{ ioerror=TRUE; ioerrornum=osError(); }
}
osClose(ifh);
osClose(ofh);
osFree(copybuf);
osDelete(file);
}
UnlockBasename(basename);
if(ioerror)
return(FALSE);
return(TRUE);
}
bool ArchiveOutbound(void)
{
struct jbList PktList;
struct osFileEntry *fe;
char buf[200];
/* Orphan files */
LogWrite(3,ACTIONINFO,"Scanning for orphan files");
if(!(osReadDir(config.cfg_PacketDir,&ArcList,IsOrphan)))
{
uint32_t err=osError();
LogWrite(1,SYSTEMERR,"Failed to read directory \"%s\"",config.cfg_PacketDir);
LogWrite(1,SYSTEMERR,"Error: %s",osErrorMsg(err));
return(FALSE);
}
SortFEList(&ArcList);
for(fe=(struct osFileEntry *)ArcList.First;fe && !ctrlc;fe=fe->Next)
{
LogWrite(1,SYSTEMINFO,"Found orphan file \"%s\", retrying...",fe->Name);
MakeFullPath(config.cfg_PacketDir,fe->Name,buf,200);
HandleOrphan(buf);
}
jbFreeList(&ArcList);
/* Read ArcList */
if(!(osReadDir(config.cfg_PacketDir,&ArcList,IsArc)))
{
uint32_t err=osError();
LogWrite(1,SYSTEMERR,"Failed to read directory \"%s\"",config.cfg_PacketDir);
LogWrite(1,SYSTEMERR,"Error: %s",osErrorMsg(err));
return(FALSE);
}
/* Delete old zero-length files */
DeleteZero(config.cfg_PacketDir,&ArcList);
/* Read index */
ReadIndex();
/* Old packets */
LogWrite(3,ACTIONINFO,"Scanning for old packets");
if(!(osReadDir(config.cfg_PacketDir,&PktList,IsPktTmp)))
{
uint32_t err=osError();
LogWrite(1,SYSTEMERR,"Failed to read directory \"%s\"",config.cfg_PacketDir);
LogWrite(1,SYSTEMERR,"Error: %s",osErrorMsg(err));
jbFreeList(&ArcList);
return(FALSE);
}
SortFEList(&PktList);
for(fe=(struct osFileEntry *)PktList.First;fe;fe=fe->Next)
{
LogWrite(1,SYSTEMINFO,"Found old packet file \"%s\", retrying...",fe->Name);
MakeFullPath(config.cfg_PacketDir,fe->Name,buf,200);
PackFile(buf);
}
jbFreeList(&PktList);
/* New packets */
LogWrite(3,ACTIONINFO,"Scanning for new files to pack");
if(!(osReadDir(config.cfg_PacketCreate,&PktList,IsNewPkt)))
{
uint32_t err=osError();
LogWrite(1,SYSTEMERR,"Failed to read directory \"%s\"",config.cfg_PacketCreate);
LogWrite(1,SYSTEMERR,"Error: %s",osErrorMsg(err));
jbFreeList(&ArcList);
return(FALSE);
}
SortFEList(&PktList);
for(fe=(struct osFileEntry *)PktList.First;fe;fe=fe->Next)
{
MakeFullPath(config.cfg_PacketCreate,fe->Name,buf,200);
if(!PackFile(buf))
if(!MakePktTmp(buf))
{
jbFreeList(&PktList);
jbFreeList(&ArcList);
return(FALSE);
}
}
jbFreeList(&PktList);
jbFreeList(&ArcList);
return(TRUE);
}

View File

@ -0,0 +1,7 @@
#define FLOW_NONE 0
#define FLOW_TRUNC 1
#define FLOW_DELETE 2
bool ArchiveOutbound(void);
void MakeBaseName(struct Node4D *n4d,char *basename);
bool AddFlow(char *filename,struct Node4D *n4d,char type,long mode);

View File

@ -0,0 +1,960 @@
#include "magimail.h"
/*************************************************************************/
/* */
/* Read Pkt */
/* */
/*************************************************************************/
#define PKT_MINREADLEN 200
bool messageend;
bool shortread,longread;
uint16_t getuword(uint8_t *buf,uint32_t offset)
{
return (uint16_t)(buf[offset]+256*buf[offset+1]);
}
void putuword(uint8_t *buf,uint32_t offset,uint16_t num)
{
buf[offset]=num%256;
buf[offset+1]=num/256;
}
uint32_t ReadNull(char *buf, uint32_t maxlen, osFile fh)
{
/* Reads from fh until buffer full or NULL */
short ch,c=0;
if(shortread) return(0);
ch=osGetChar(fh);
while(ch!=-1 && ch!=0 && c!=maxlen-1)
{
buf[c++]=ch;
ch=osGetChar(fh);
}
buf[c]=0;
if(ch==-1)
shortread=TRUE;
if(ch!=0 && c==maxlen-1)
longread=TRUE;
return(c);
}
uint32_t ReadCR(char *buf, uint32_t maxlen, osFile fh)
{
/* Reads from fh until buffer full or CR */
short ch,c=0;
ch=osGetChar(fh);
while(ch!=-1 && ch!=0 && ch!=10 && ch !=13 && c!=maxlen-2)
{
buf[c++]=ch;
if(c!=maxlen-2) ch=osGetChar(fh);
}
if(ch==13 || ch==10)
buf[c++]=ch;
buf[c]=0;
if(ch==0) messageend=TRUE;
if(ch==-1) shortread=TRUE;
return(c);
}
bool ReadPkt(char *pkt,struct osFileEntry *fe,bool bundled,bool (*handlefunc)(struct MemMessage *mm))
{
osFile fh;
struct Aka *tmpaka;
struct ConfigNode *tmpcnode;
uint32_t msgnum,msgoffset;
char buf[200];
uint8_t PktHeader[SIZE_PKTHEADER];
uint8_t PktMsgHeader[SIZE_PKTMSGHEADER];
struct Node4D PktOrig,PktDest;
char *monthnames[]={"Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec","???"};
struct MemMessage *mm;
struct TextChunk *chunk;
bool pkt_pw,pkt_4d,pkt_5d;
int res;
if(config.cfg_BeforeToss[0])
{
ExpandPacker(config.cfg_BeforeToss,buf,200,"",pkt);
res=osExecute(buf);
if(res != 0)
{
LogWrite(1,SYSTEMERR,"BEFORETOSS command failed for %s: %u",pkt,res);
return(FALSE);
}
}
shortread=FALSE;
longread=FALSE;
pkt_pw=FALSE;
pkt_4d=FALSE;
pkt_5d=FALSE;
PktOrig.Zone=0;
PktOrig.Net=0;
PktOrig.Node=0;
PktOrig.Point=0;
PktDest.Zone=0;
PktDest.Net=0;
PktDest.Node=0;
PktDest.Point=0;
if(!(mm=mmAlloc()))
return(FALSE);
if(!(fh=osOpen(pkt,MODE_OLDFILE)))
{
uint32_t err=osError();
LogWrite(1,SYSTEMERR,"Unable to open %s",pkt);
LogWrite(1,SYSTEMERR,"Error: %s",osErrorMsg(err));
mmFree(mm);
return(TRUE);
}
if(osRead(fh,PktHeader,SIZE_PKTHEADER)!=SIZE_PKTHEADER)
{
LogWrite(1,TOSSINGERR,"Packet header in %s is too short",pkt);
osClose(fh);
mmFree(mm);
BadFile(pkt,"Packet header is too short");
return(TRUE);
}
if(getuword(PktHeader,PKTHEADER_PKTTYPE)!=0x0002)
{
LogWrite(1,TOSSINGERR,"%s is not a Type-2 packet",pkt);
osClose(fh);
mmFree(mm);
BadFile(pkt,"Not a Type-2 packet");
return(TRUE);
}
if(getuword(PktHeader,PKTHEADER_BAUD) == 2)
{
/* PktOrig och PktDest */
PktOrig.Zone = getuword(PktHeader,PKTHEADER_ORIGZONE);
PktOrig.Net = getuword(PktHeader,PKTHEADER_ORIGNET);
PktOrig.Node = getuword(PktHeader,PKTHEADER_ORIGNODE);
PktOrig.Point = getuword(PktHeader,PKTHEADER_ORIGPOINT);
PktDest.Zone = getuword(PktHeader,PKTHEADER_DESTZONE);
PktDest.Net = getuword(PktHeader,PKTHEADER_DESTNET);
PktDest.Node = getuword(PktHeader,PKTHEADER_DESTNODE);
PktDest.Point = getuword(PktHeader,PKTHEADER_DESTPOINT);
pkt_5d=TRUE;
}
else
{
/* PktOrig och PktDest */
if(getuword(PktHeader,PKTHEADER_ORIGZONE))
{
PktOrig.Zone = getuword(PktHeader,PKTHEADER_ORIGZONE);
PktDest.Zone = getuword(PktHeader,PKTHEADER_DESTZONE);
}
else if(getuword(PktHeader,PKTHEADER_QORIGZONE))
{
PktOrig.Zone= getuword(PktHeader,PKTHEADER_QORIGZONE);
PktDest.Zone= getuword(PktHeader,PKTHEADER_QDESTZONE);
}
else
{
PktOrig.Zone=0;
PktDest.Zone=0;
}
PktOrig.Net = getuword(PktHeader,PKTHEADER_ORIGNET);
PktOrig.Node = getuword(PktHeader,PKTHEADER_ORIGNODE);
PktDest.Net = getuword(PktHeader,PKTHEADER_DESTNET);
PktDest.Node = getuword(PktHeader,PKTHEADER_DESTNODE);
if(PktHeader[PKTHEADER_CWVALIDCOPY] == PktHeader[PKTHEADER_CAPABILWORD+1] &&
PktHeader[PKTHEADER_CWVALIDCOPY+1] == PktHeader[PKTHEADER_CAPABILWORD])
{
pkt_4d=TRUE;
if(getuword(PktHeader,PKTHEADER_ORIGPOINT)!=0 && getuword(PktHeader,PKTHEADER_ORIGNET)==0xffff)
PktOrig.Net = getuword(PktHeader,PKTHEADER_AUXNET);
PktOrig.Point = getuword(PktHeader,PKTHEADER_ORIGPOINT);
PktDest.Point = getuword(PktHeader,PKTHEADER_DESTPOINT);
}
}
/* Check packet destination */
if((config.cfg_Flags & CFG_CHECKPKTDEST) && !no_security)
{
for(tmpaka=(struct Aka *)config.AkaList.First;tmpaka;tmpaka=tmpaka->Next)
if(Compare4D(&tmpaka->Node,&PktDest) == 0) break;
if(!tmpaka)
{
LogWrite(1,TOSSINGERR,"Addressed to %u:%u/%u.%u, not to me",PktDest.Zone,PktDest.Net,PktDest.Node,PktDest.Point);
osClose(fh);
mmFree(mm);
sprintf(buf,"Addressed to %u:%u/%u.%u, not to me",PktDest.Zone,PktDest.Net,PktDest.Node,PktDest.Point);
BadFile(pkt,buf);
return(TRUE);
}
}
/* Fixa zone */
if(PktOrig.Zone == 0)
for(tmpcnode=(struct ConfigNode *)config.CNodeList.First;tmpcnode;tmpcnode=tmpcnode->Next)
{
if(Compare4D(&PktOrig,&tmpcnode->Node)==0)
{
PktOrig.Zone=tmpcnode->Node.Zone;
break;
}
}
if(PktDest.Zone == 0)
for(tmpaka=(struct Aka *)config.AkaList.First;tmpaka;tmpaka=tmpaka->Next)
{
if(Compare4D(&PktDest,&tmpaka->Node)==0)
{
PktDest.Zone=tmpaka->Node.Zone;
break;
}
}
if(PktOrig.Zone == 0) PktOrig.Zone=config.cfg_DefaultZone;
if(PktDest.Zone == 0) PktDest.Zone=config.cfg_DefaultZone;
for(tmpcnode=(struct ConfigNode *)config.CNodeList.First;tmpcnode;tmpcnode=tmpcnode->Next)
if(Compare4D(&PktOrig,&tmpcnode->Node)==0) break;
if(tmpcnode)
{
if(tmpcnode->PacketPW[0]!=0 && PktHeader[PKTHEADER_PASSWORD]!=0)
pkt_pw=TRUE;
}
buf[0]=0;
if(pkt_pw) strcat(buf,", pw");
if(pkt_4d) strcat(buf,", 4d");
if(pkt_5d) strcat(buf,", 5d");
if(buf[0] != 0)
buf[0]='/';
if(pkt_5d)
{
char domain[10];
mystrncpy(domain,(char *)&PktHeader[PKTHEADER45_ORIGDOMAIN],9);
LogWrite(1,ACTIONINFO,"Tossing %s (%uK) from %d:%d/%d.%d@%s %s",
fe->Name,
(fe->Size+512)/1024,
PktOrig.Zone,
PktOrig.Net,
PktOrig.Node,
PktOrig.Point,
domain,
buf);
}
else
{
int month;
month=getuword(PktHeader,PKTHEADER_MONTH);
if(month > 11)
month=12;
LogWrite(1,ACTIONINFO,"Tossing %s (%uK) from %d:%d/%d.%d (%02d-%s-%02d %02d:%02d:%02d) %s",
fe->Name,
(fe->Size+512)/1024,
PktOrig.Zone,
PktOrig.Net,
PktOrig.Node,
PktOrig.Point,
getuword(PktHeader,PKTHEADER_DAY),
monthnames[month],
getuword(PktHeader,PKTHEADER_YEAR) % 100,
getuword(PktHeader,PKTHEADER_HOUR),
getuword(PktHeader,PKTHEADER_MINUTE),
getuword(PktHeader,PKTHEADER_SECOND),
buf);
}
if(tmpcnode)
{
strncpy(buf,(char *)&PktHeader[PKTHEADER_PASSWORD],8);
buf[8]=0;
if(tmpcnode->PacketPW[0]!=0 && stricmp(buf,tmpcnode->PacketPW)!=0 && !no_security)
{
LogWrite(1,TOSSINGERR,"Wrong password");
osClose(fh);
mmFree(mm);
BadFile(pkt,"Wrong password");
return(TRUE);
}
}
msgoffset=osFTell(fh);
if(osRead(fh,PktMsgHeader,SIZE_PKTMSGHEADER) < 2)
{
LogWrite(1,TOSSINGERR,"Message header for msg #1 (offset %d) is too short",msgoffset);
osClose(fh);
mmFree(mm);
sprintf(buf,"Message header for msg #1 (offset %d) is too short",msgoffset);
BadFile(pkt,buf);
return(TRUE);
}
msgnum=0;
while(getuword(PktMsgHeader,PKTMSGHEADER_PKTTYPE) == 2 && !ctrlc)
{
msgnum++;
printf("Message %u \x0d",msgnum);
fflush(stdout);
/* Init variables */
mmClear(mm);
mm->OrigNode.Net = getuword(PktMsgHeader,PKTMSGHEADER_ORIGNET);
mm->OrigNode.Node = getuword(PktMsgHeader,PKTMSGHEADER_ORIGNODE);
mm->DestNode.Net = getuword(PktMsgHeader,PKTMSGHEADER_DESTNET);
mm->DestNode.Node = getuword(PktMsgHeader,PKTMSGHEADER_DESTNODE);
mm->DestNode.Zone=PktDest.Zone;
mm->DestNode.Zone=PktOrig.Zone;
mm->Attr=getuword(PktMsgHeader,PKTMSGHEADER_ATTR);
mm->Cost=getuword(PktMsgHeader,PKTMSGHEADER_COST);
Copy4D(&mm->PktOrig,&PktOrig);
Copy4D(&mm->PktDest,&PktDest);
if(no_security)
mm->Flags |= MMFLAG_NOSECURITY;
/* Get header strings */
ReadNull(mm->DateTime,20,fh);
ReadNull(mm->To,36,fh);
ReadNull(mm->From,36,fh);
ReadNull(mm->Subject,72,fh);
/* Corrupt packet? */
if(shortread)
{
LogWrite(1,TOSSINGERR,"Message header for msg #%u (offset %d) is short",msgnum,msgoffset);
sprintf(buf,"Message header for msg #%u (offset %d) is short",msgnum,msgoffset);
osClose(fh);
mmFree(mm);
BadFile(pkt,buf);
return(TRUE);
}
if(longread)
{
LogWrite(1,TOSSINGERR,"Header strings too long in msg #%u (offset %d)",msgnum,msgoffset);
sprintf(buf,"Header strings too long in msg #%u (offset %d)",msgnum,msgoffset);
osClose(fh);
mmFree(mm);
BadFile(pkt,buf);
return(TRUE);
}
/* Start reading message text */
messageend=FALSE;
ReadCR(buf,200,fh);
/* Echomail or netmail? */
if(strncmp(buf,"AREA:",5)==0)
{
mystrncpy(mm->Area,&buf[5],80);
stripleadtrail(mm->Area); /* Strip spaces from area name */
}
else
{
if(!mmAddLine(mm,buf))
{
osClose(fh);
mmFree(mm);
return(FALSE);
}
}
/* Get rest of text */
while(!messageend)
{
ReadCR(buf,200,fh);
if(shortread)
{
osClose(fh);
mmFree(mm);
LogWrite(1,TOSSINGERR,"Got unexpected EOF when reading msg #%u (offset %d)",msgnum,msgoffset);
sprintf(buf,"Got unexpected EOF when reading msg #%u (offset %d)",msgnum,msgoffset);
BadFile(pkt,buf);
return(TRUE);
}
if(buf[0])
{
if(!mmAddLine(mm,buf))
{
osClose(fh);
mmFree(mm);
return(FALSE);
}
}
}
/* Stats */
for(tmpcnode=(struct ConfigNode *)config.CNodeList.First;tmpcnode;tmpcnode=tmpcnode->Next)
if(Compare4D(&tmpcnode->Node,&mm->PktOrig)==0) break;
if(tmpcnode)
{
uint32_t size;
size=0;
for(chunk=(struct TextChunk *)mm->TextChunks.First;chunk;chunk=chunk->Next)
size+=chunk->Length;
if(mm->Area[0])
{
tmpcnode->GotEchomails++;
tmpcnode->GotEchomailBytes+=size;
}
else
{
tmpcnode->GotNetmails++;
tmpcnode->GotNetmailBytes+=size;
}
}
toss_read++;
mm->Flags |= MMFLAG_TOSSED;
if(!(*handlefunc)(mm))
{
osClose(fh);
mmFree(mm);
return(FALSE);
}
msgoffset=osFTell(fh);
if(osRead(fh,PktMsgHeader,SIZE_PKTMSGHEADER) < 2)
{
LogWrite(1,TOSSINGERR,"Packet header too short for msg #%u (offset %d)",msgnum+1,msgoffset);
osClose(fh);
mmFree(mm);
sprintf(buf,"Packet header too short for msg #%u (offset %d)",msgnum+1,msgoffset);
BadFile(pkt,buf);
return(TRUE);
}
}
if(getuword(PktMsgHeader,PKTMSGHEADER_PKTTYPE)!=0)
{
osClose(fh);
mmFree(mm);
LogWrite(1,TOSSINGERR,"Unknown message type %u for message #%u (offset %d)",getuword(PktMsgHeader,PKTMSGHEADER_PKTTYPE),msgnum+1,msgoffset);
sprintf(buf,"Unknown message type %u for message #%u (offset %d)",getuword(PktMsgHeader,PKTMSGHEADER_PKTTYPE),msgnum+1,msgoffset);
BadFile(pkt,buf);
return(TRUE);
}
printf(" \x0d");
fflush(stdout);
osClose(fh);
return(TRUE);
}
/*************************************************************************/
/* */
/* Write Pkt */
/* */
/*************************************************************************/
struct Pkt
{
struct Pkt *Next;
osFile fh;
uint32_t hexnum;
uint32_t Len;
uint16_t Type;
struct Node4D Dest;
struct Node4D Orig;
};
void pktWrite(struct Pkt *pkt,uint8_t *buf,uint32_t len)
{
if(!osWrite(pkt->fh,buf,len))
{ ioerror=TRUE; ioerrornum=osError(); }
pkt->Len+=len;
}
void WriteNull(struct Pkt *pkt,char *str)
{
pktWrite(pkt,(uint8_t *)str,(uint32_t)(strlen(str)+1));
}
struct Pkt *FindPkt(struct Node4D *node,struct Node4D *mynode,uint16_t type)
{
struct Pkt *pkt;
for(pkt=(struct Pkt *)PktList.First;pkt;pkt=pkt->Next)
if(Compare4D(node,&pkt->Dest)==0 && Compare4D(mynode,&pkt->Orig)==0 && type==pkt->Type)
return(pkt);
return(NULL);
}
time_t lastt;
uint32_t serial;
struct Pkt *CreatePkt(struct Node4D *dest,struct ConfigNode *node,struct Node4D *orig,uint16_t type)
{
char buf[100],buf2[100];
struct Pkt *pkt;
uint32_t num,c;
time_t t;
struct tm *tp;
uint8_t PktHeader[SIZE_PKTHEADER];
do
{
t=time(NULL);
if(t == lastt) serial++;
else serial=0;
if(serial == 256) serial=0;
lastt=t;
num = (t<<8) + serial;
sprintf(buf2,"%08x.newpkt",num);
MakeFullPath(config.cfg_PacketCreate,buf2,buf,100);
} while(osExists(buf));
if(!(pkt=(struct Pkt *)osAllocCleared(sizeof(struct Pkt))))
{
nomem=TRUE;
return(NULL);
}
if(!(pkt->fh=osOpen(buf,MODE_NEWFILE)))
{
uint32_t err=osError();
LogWrite(1,SYSTEMERR,"Unable to create packet %s",buf);
LogWrite(1,SYSTEMERR,"Error: %s",osErrorMsg(err));
osFree(pkt);
return(NULL);
}
pkt->hexnum=num;
pkt->Type=type;
Copy4D(&pkt->Dest,dest);
Copy4D(&pkt->Orig,orig);
putuword(PktHeader,PKTHEADER_ORIGNODE,orig->Node);
putuword(PktHeader,PKTHEADER_DESTNODE,dest->Node);
time(&t);
tp=localtime(&t);
putuword(PktHeader,PKTHEADER_DAY,tp->tm_mday);
putuword(PktHeader,PKTHEADER_MONTH,tp->tm_mon);
putuword(PktHeader,PKTHEADER_YEAR,tp->tm_year+1900);
putuword(PktHeader,PKTHEADER_HOUR,tp->tm_hour);
putuword(PktHeader,PKTHEADER_MINUTE,tp->tm_min);
putuword(PktHeader,PKTHEADER_SECOND,tp->tm_sec);
putuword(PktHeader,PKTHEADER_BAUD,0);
putuword(PktHeader,PKTHEADER_PKTTYPE,2);
putuword(PktHeader,PKTHEADER_ORIGNET,orig->Net);
putuword(PktHeader,PKTHEADER_DESTNET,dest->Net);
PktHeader[PKTHEADER_PRODCODELOW]=0xfe;
PktHeader[PKTHEADER_REVMAJOR]=VERSION_MAJOR;
putuword(PktHeader,PKTHEADER_QORIGZONE,orig->Zone);
putuword(PktHeader,PKTHEADER_QDESTZONE,dest->Zone);
putuword(PktHeader,PKTHEADER_AUXNET,0);
putuword(PktHeader,PKTHEADER_CWVALIDCOPY,0x0100);
PktHeader[PKTHEADER_PRODCODEHIGH]=0;
PktHeader[PKTHEADER_REVMINOR]=VERSION_MINOR;
putuword(PktHeader,PKTHEADER_CAPABILWORD,0x0001);
putuword(PktHeader,PKTHEADER_ORIGZONE,orig->Zone);
putuword(PktHeader,PKTHEADER_DESTZONE,dest->Zone);
putuword(PktHeader,PKTHEADER_ORIGPOINT,orig->Point);
putuword(PktHeader,PKTHEADER_DESTPOINT,dest->Point);
PktHeader[PKTHEADER_PRODDATA]=0;
PktHeader[PKTHEADER_PRODDATA+1]=0;
PktHeader[PKTHEADER_PRODDATA+2]=0;
PktHeader[PKTHEADER_PRODDATA+3]=0;
for(c=0;c<8;c++)
PktHeader[PKTHEADER_PASSWORD+c]=0;
if(node)
strncpy((char *)&PktHeader[PKTHEADER_PASSWORD],node->PacketPW,8);
pktWrite(pkt,PktHeader,SIZE_PKTHEADER);
if(ioerror)
{
osClose(pkt->fh);
osFree(pkt);
return(NULL);
}
return(pkt);
}
void FinishPacket(struct Pkt *pkt)
{
pktWrite(pkt,(uint8_t *)"",1);
pktWrite(pkt,(uint8_t *)"",1);
osClose(pkt->fh);
if(pkt->hexnum)
{
char oldname[200],newname[200],buf1[100],buf2[100],*typestr;
/* Create packet name */
switch(pkt->Type)
{
case PKTS_HOLD: typestr="Hold";
break;
case PKTS_NORMAL: typestr="Normal";
break;
case PKTS_DIRECT: typestr="Direct";
break;
case PKTS_CRASH: typestr="Crash";
break;
case PKTS_ECHOMAIL: typestr="Echomail";
break;
}
sprintf(buf1,"%08x.newpkt",pkt->hexnum);
sprintf(buf2,"%08x_%s_%d_%d_%d_%d.newpkt",
pkt->hexnum,
typestr,
pkt->Dest.Zone,
pkt->Dest.Net,
pkt->Dest.Node,
pkt->Dest.Point);
MakeFullPath(config.cfg_PacketCreate,buf1,oldname,200);
MakeFullPath(config.cfg_PacketCreate,buf2,newname,200);
if(!osRename(oldname,newname))
{
uint32_t err=osError();
LogWrite(1,SYSTEMERR,"Failed to rename %s to %s",oldname,newname);
LogWrite(1,SYSTEMERR,"Error: %s",osErrorMsg(err));
}
}
jbFreeNode(&PktList,(struct jbNode *)pkt);
}
void ClosePackets(void)
{
struct Pkt *pkt,*pkt2;
pkt=(struct Pkt *)PktList.First;
while(pkt)
{
pkt2=pkt->Next;
FinishPacket(pkt);
pkt=pkt2;
}
}
bool WriteMsgHeader(struct Pkt *pkt,struct MemMessage *mm)
{
uint8_t PktMsgHeader[SIZE_PKTMSGHEADER];
putuword(PktMsgHeader,PKTMSGHEADER_PKTTYPE,0x0002);
putuword(PktMsgHeader,PKTMSGHEADER_ORIGNODE,mm->OrigNode.Node);
putuword(PktMsgHeader,PKTMSGHEADER_DESTNODE,mm->DestNode.Node);
putuword(PktMsgHeader,PKTMSGHEADER_ORIGNET,mm->OrigNode.Net);
putuword(PktMsgHeader,PKTMSGHEADER_DESTNET,mm->DestNode.Net);
putuword(PktMsgHeader,PKTMSGHEADER_ATTR,mm->Attr);
putuword(PktMsgHeader,PKTMSGHEADER_COST,mm->Cost);
pktWrite(pkt,PktMsgHeader,SIZE_PKTMSGHEADER);
WriteNull(pkt,mm->DateTime);
WriteNull(pkt,mm->To);
WriteNull(pkt,mm->From);
WriteNull(pkt,mm->Subject);
if(ioerror)
return(FALSE);
return(TRUE);
}
bool WritePath(struct Pkt *pkt,struct jbList *list)
{
uint16_t c;
struct Path *path;
for(path=(struct Path *)list->First;path;path=path->Next)
for(c=0;c<path->Paths;c++)
if(path->Path[c][0]!=0)
{
pktWrite(pkt,(uint8_t *)"\x01PATH: ",7);
pktWrite(pkt,(uint8_t *)path->Path[c],(uint32_t)strlen(path->Path[c]));
pktWrite(pkt,(uint8_t *)"\x0d",1);
}
if(ioerror)
return(FALSE);
return(TRUE);
}
bool WriteSeenBy(struct Pkt *pkt,struct jbList *list)
{
char *buf;
if(!(buf=mmMakeSeenByBuf(list)))
return(FALSE);
pktWrite(pkt,(uint8_t *)buf,(uint32_t)strlen(buf));
osFree(buf);
return(TRUE);
}
bool WriteEchoMail(struct MemMessage *mm,struct ConfigNode *node, struct Aka *aka)
{
char buf[100];
struct Node4D *From4D;
struct Pkt *pkt;
struct TextChunk *chunk;
uint32_t size;
From4D=&aka->Node;
if(node->Flags & NODE_PKTFROM)
From4D=&node->PktFrom;
toss_written++;
mm->Type=PKTS_ECHOMAIL;
size=0;
for(chunk=(struct TextChunk *)mm->TextChunks.First;chunk;chunk=chunk->Next)
size+=chunk->Length;
node->SentEchomails++;
node->SentEchomailBytes+=size;
pkt=FindPkt(&node->Node,From4D,mm->Type);
if(!pkt || (pkt && config.cfg_MaxPktSize!=0 && pkt->Len > config.cfg_MaxPktSize))
{
if(pkt) FinishPacket(pkt);
if(!(pkt=CreatePkt(&node->Node,node,From4D,mm->Type)))
{
return(FALSE);
}
jbAddNode(&PktList,(struct jbNode *)pkt);
}
Copy4D(&mm->DestNode,&node->Node);
Copy4D(&mm->OrigNode,From4D);
if(!WriteMsgHeader(pkt,mm))
return(FALSE);
sprintf(buf,"AREA:%s\x0d",mm->Area);
pktWrite(pkt,(uint8_t *)buf,(uint32_t)strlen(buf));
if(ioerror)
return(FALSE);
for(chunk=(struct TextChunk *)mm->TextChunks.First;chunk;chunk=chunk->Next)
{
pktWrite(pkt,(uint8_t *)chunk->Data,chunk->Length);
if(ioerror)
return(FALSE);
}
if(node->Node.Zone != aka->Node.Zone || (node->Flags & NODE_TINYSEENBY))
{
struct jbList seenbylist;
struct Nodes2D *seenby;
if(!(seenby=(struct Nodes2D *)osAlloc(sizeof(struct Nodes2D))))
{
nomem=TRUE;
return(FALSE);
}
seenby->Nodes=0;
seenby->Next=NULL;
jbNewList(&seenbylist);
jbAddNode(&seenbylist,(struct jbNode *)seenby);
if(node->Node.Point == 0)
if(!mmAddNodes2DList(&seenbylist,node->Node.Net,node->Node.Node))
{
jbFreeList(&seenbylist);
return(FALSE);
}
if(aka->Node.Point == 0)
if(!mmAddNodes2DList(&seenbylist,aka->Node.Net,aka->Node.Node))
{
jbFreeList(&seenbylist);
return(FALSE);
}
if(!mmSortNodes2D(&seenbylist))
{
jbFreeList(&seenbylist);
return(FALSE);
}
if(!WriteSeenBy(pkt,&seenbylist))
{
jbFreeList(&seenbylist);
return(FALSE);
}
jbFreeList(&seenbylist);
}
else if(!(node->Flags & NODE_NOSEENBY))
{
if(!mmSortNodes2D(&mm->SeenBy))
return(FALSE);
if(!WriteSeenBy(pkt,&mm->SeenBy))
return(FALSE);
}
if(!WritePath(pkt,&mm->Path))
return(FALSE);
pktWrite(pkt,(uint8_t *)"",1);
return(TRUE);
}
bool WriteNetMail(struct MemMessage *mm,struct Node4D *dest,struct Aka *aka)
{
struct Pkt *pkt;
struct ConfigNode *cnode;
struct TextChunk *chunk;
struct Node4D *From4D;
uint32_t size;
toss_written++;
From4D=&aka->Node;
for(cnode=(struct ConfigNode *)config.CNodeList.First;cnode;cnode=cnode->Next)
if(Compare4D(&cnode->Node,dest)==0) break;
if(cnode)
{
/* Calculate size */
size=0;
for(chunk=(struct TextChunk *)mm->TextChunks.First;chunk;chunk=chunk->Next)
size+=chunk->Length;
cnode->SentNetmails++;
cnode->SentNetmailBytes+=size;
if(cnode->Flags & NODE_PACKNETMAIL)
if(mm->Type == PKTS_NORMAL) mm->Type=PKTS_ECHOMAIL;
if(cnode->Flags & NODE_PKTFROM)
From4D=&cnode->PktFrom;
}
pkt=FindPkt(dest,From4D,mm->Type);
if(!pkt || (pkt && config.cfg_MaxPktSize!=0 && pkt->Len > config.cfg_MaxPktSize))
{
if(pkt) FinishPacket(pkt);
if(!(pkt=CreatePkt(dest,cnode,From4D,mm->Type)))
{
return(FALSE);
}
jbAddNode(&PktList,(struct jbNode *)pkt);
}
if(!WriteMsgHeader(pkt,mm))
return(FALSE);
for(chunk=(struct TextChunk *)mm->TextChunks.First;chunk;chunk=chunk->Next)
{
pktWrite(pkt,(uint8_t *)chunk->Data,chunk->Length);
if(ioerror)
return(FALSE);
}
pktWrite(pkt,(uint8_t *)"",1);
return(TRUE);
}

View File

@ -0,0 +1,6 @@
bool ReadPkt(char *pkt,struct osFileEntry *fe,bool bundled,bool (*handlefunc)(struct MemMessage *mm));
bool WriteEchoMail(struct MemMessage *mm,struct ConfigNode *cnode, struct Aka *aka);
bool WriteNetMail(struct MemMessage *mm,struct Node4D *dest,struct Aka *aka);
void ClosePackets(void);

View File

@ -0,0 +1,24 @@
#include "magimail.h"
bool SafeDelete(char *file)
{
struct osFileEntry *fe;
if(!(fe=osAllocCleared(sizeof(struct osFileEntry))))
return(FALSE);
mystrncpy(fe->Name,file,100);
jbAddNode(&DeleteList,(struct jbNode *)fe);
return(TRUE);
}
void ProcessSafeDelete(void)
{
struct osFileEntry *fe;
for(fe=(struct osFileEntry *)DeleteList.First;fe;fe=fe->Next)
osDelete(fe->Name);
jbFreeList(&DeleteList);
}

View File

@ -0,0 +1,2 @@
bool SafeDelete(char *file);
void ProcessSafeDelete(void);

View File

@ -0,0 +1,306 @@
#include "magimail.h"
void LogScanResults(void)
{
printf("\n");
if(scan_total==0)
LogWrite(2,TOSSINGINFO,"No messages exported");
else if(scan_total==1)
LogWrite(2,TOSSINGINFO,"1 message exported");
else
{
LogWrite(2,TOSSINGINFO,"%u messages exported",scan_total);
}
}
bool ScanHandle(struct MemMessage *mm)
{
char buf[50];
if(mm->Area[0]==0)
{
Print4D(&mm->DestNode,buf);
LogWrite(4,TOSSINGINFO,"Exporting message #%u from \"%s\" to \"%s\" at %s",
mm->msgnum,
mm->From,
mm->To,
buf);
}
else
{
LogWrite(4,TOSSINGINFO,"Exporting message #%u from \"%s\" to \"%s\" in %s",
mm->msgnum,
mm->From,
mm->To,
mm->Area);
}
return HandleMessage(mm);
}
bool Scan(void)
{
struct Area *area;
LogWrite(2,ACTIONINFO,"Scanning all areas for messages to export");
if(!BeforeScanToss())
return(FALSE);
for(area=(struct Area *)config.AreaList.First;area && !ctrlc;area=area->Next)
if(area->Messagebase && (area->AreaType == AREATYPE_ECHOMAIL || area->AreaType == AREATYPE_NETMAIL))
{
if(area->Messagebase->exportfunc)
{
if(area->AreaType == AREATYPE_NETMAIL && (config.cfg_Flags & CFG_NOEXPORTNETMAIL))
{
printf("Skipping area %s (NOEXPORTNETMAIL is set)\n", area->Tagname);
}
else
{
printf("Scanning area %s\n",area->Tagname);
if(!(*area->Messagebase->exportfunc)(area,ScanHandle))
{
AfterScanToss(FALSE);
return(FALSE);
}
}
}
}
if(ctrlc)
{
AfterScanToss(FALSE);
return(FALSE);
}
LogScanResults();
AfterScanToss(TRUE);
return(TRUE);
}
bool ScanList(char *file)
{
osFile fh;
char buf[100];
struct Area *area;
int res;
LogWrite(2,ACTIONINFO,"Scanning areas in %s for messages to export",file);
if(!(fh=osOpen(file,MODE_OLDFILE)))
{
LogWrite(1,USERERR,"Unable to open %s",file);
return(FALSE);
}
if(!BeforeScanToss())
return(FALSE);
while(osFGets(fh,buf,100) && !ctrlc)
{
striptrail(buf);
if(buf[0] != 0)
{
striptrail(buf);
for(area=(struct Area *)config.AreaList.First;area;area=area->Next)
if(stricmp(area->Tagname,buf)==0) break;
if(!area)
{
LogWrite(1,USERERR,"Skipping area %s, area is unknown",buf);
}
else if(!area->scanned)
{
area->scanned=TRUE;
if(area->AreaType != AREATYPE_ECHOMAIL && area->AreaType != AREATYPE_NETMAIL)
{
LogWrite(1,USERERR,"Skipping area %s, not an echomail or netmail area",area->Tagname);
}
else if(area->AreaType == AREATYPE_NETMAIL && (config.cfg_Flags & CFG_NOEXPORTNETMAIL))
{
LogWrite(1,USERERR,"Skipping area %s (NOEXPORTNETMAIL is set)", area->Tagname);
}
else if(!area->Messagebase)
{
LogWrite(1,USERERR,"Skipping area %s, area is pass-through",area->Tagname);
}
else if(!area->Messagebase->exportfunc)
{
LogWrite(1,USERERR,"Skipping area %s, scanning is not supported for this type of messagebase",area->Tagname);
}
else
{
printf("Scanning area %s\n",area->Tagname);
res=(*area->Messagebase->exportfunc)(area,ScanHandle);
if(!res)
{
AfterScanToss(FALSE);
osClose(fh);
return(FALSE);
}
}
}
}
}
osClose(fh);
if(ctrlc)
{
AfterScanToss(FALSE);
return(FALSE);
}
LogScanResults();
AfterScanToss(TRUE);
return(TRUE);
}
bool ScanDotJam(char *file)
{
osFile fh;
char buf[100];
struct Area *area;
int res;
LogWrite(2,ACTIONINFO,"Scanning areas in %s for messages to export",file);
if(!(fh=osOpen(file,MODE_OLDFILE)))
{
LogWrite(1,USERERR,"Unable to open %s",file);
return(FALSE);
}
if(!BeforeScanToss())
return(FALSE);
while(osFGets(fh,buf,100) && !ctrlc)
{
striptrail(buf);
if(buf[0] != 0)
{
striptrail(buf);
if(strchr(buf,' '))
*strchr(buf,' ')=0;
for(area=(struct Area *)config.AreaList.First;area;area=area->Next)
if(stricmp(area->Path,buf)==0) break;
if(!area)
{
LogWrite(1,USERERR,"No area with path %s",buf);
}
else if(!area->scanned)
{
area->scanned=TRUE;
if(area->AreaType != AREATYPE_ECHOMAIL && area->AreaType != AREATYPE_NETMAIL)
{
LogWrite(1,USERERR,"Skipping area %s, not an echomail or netmail area",area->Tagname);
}
else if(area->AreaType == AREATYPE_NETMAIL && (config.cfg_Flags & CFG_NOEXPORTNETMAIL))
{
LogWrite(1,USERERR,"Skipping area %s (NOEXPORTNETMAIL is set)", area->Tagname);
}
else if(!area->Messagebase)
{
LogWrite(1,USERERR,"Skipping area %s, area is pass-through",area->Tagname);
}
else if(!area->Messagebase->exportfunc)
{
LogWrite(1,USERERR,"Skipping area %s, scanning is not supported for this type of messagebase",area->Tagname);
}
else
{
printf("Scanning area %s\n",area->Tagname);
res=(*area->Messagebase->exportfunc)(area,ScanHandle);
if(!res)
{
AfterScanToss(FALSE);
osClose(fh);
return(FALSE);
}
}
}
}
}
osClose(fh);
if(ctrlc)
{
AfterScanToss(FALSE);
return(FALSE);
}
LogScanResults();
AfterScanToss(TRUE);
return(TRUE);
}
bool ScanArea(char *tagname)
{
struct Area *area;
int res;
for(area=(struct Area *)config.AreaList.First;area;area=area->Next)
if(stricmp(area->Tagname,tagname)==0) break;
if(!area)
{
LogWrite(1,USERERR,"Unknown area %s",tagname);
return(FALSE);
}
if(area->AreaType != AREATYPE_ECHOMAIL && area->AreaType != AREATYPE_NETMAIL)
{
LogWrite(1,USERERR,"You cannot scan area %s, not an echomail or netmail area",area->Tagname);
return(FALSE);
}
else if(!area->Messagebase)
{
LogWrite(1,USERERR,"You cannot scan area %s, area is pass-through",area->Tagname);
return(FALSE);
}
else if(!area->Messagebase->exportfunc)
{
LogWrite(1,USERERR,"You cannot scan area %s, scanning is not supported for this type of messagebase",area->Tagname);
return(FALSE);
}
if(!BeforeScanToss())
return(FALSE);
printf("Scanning area %s\n",area->Tagname);
res=(*area->Messagebase->exportfunc)(area,ScanHandle);
if(!res)
{
AfterScanToss(FALSE);
return(FALSE);
}
LogScanResults();
AfterScanToss(TRUE);
return(TRUE);
}

View File

@ -0,0 +1,4 @@
bool Scan(void);
bool ScanList(char *file);
bool ScanDotJam(char *file);
bool ScanArea(char *tagname);

View File

@ -0,0 +1,191 @@
#include "magimail.h"
#define STATS_IDENTIFIER "CST3"
struct DiskAreaStats
{
char Tagname[80];
struct Node4D Aka;
char Group;
char fill_to_make_even; /* Just ignore this one */
uint32_t TotalTexts;
uint16_t Last8Days[8];
uint32_t Dupes;
time_t FirstTime;
time_t LastTime;
};
struct DiskNodeStats
{
struct Node4D Node;
uint32_t GotNetmails;
uint32_t GotNetmailBytes;
uint32_t SentNetmails;
uint32_t SentNetmailBytes;
uint32_t GotEchomails;
uint32_t GotEchomailBytes;
uint32_t SentEchomails;
uint32_t SentEchomailBytes;
uint32_t Dupes;
time_t FirstTime;
};
bool WriteStats(char *file)
{
struct Area *area;
struct ConfigNode *cnode;
struct DiskAreaStats dastat;
struct DiskNodeStats dnstat;
osFile fh;
uint32_t areas,nodes;
if(!(fh=osOpen(file,MODE_NEWFILE)))
{
uint32_t err=osError();
LogWrite(1,SYSTEMERR,"Unable to open %s for writing",file);
LogWrite(1,SYSTEMERR,"Error: %s",osErrorMsg(err));
return(FALSE);
}
areas=0;
nodes=0;
for(area=(struct Area *)config.AreaList.First;area;area=area->Next)
if(area->AreaType == AREATYPE_BAD || area->AreaType == AREATYPE_ECHOMAIL || area->AreaType == AREATYPE_NETMAIL)
{
if(!(area->Flags & AREA_UNCONFIRMED))
areas++;
}
for(cnode=(struct ConfigNode *)config.CNodeList.First;cnode;cnode=cnode->Next)
nodes++;
if(DayStatsWritten == 0)
DayStatsWritten = time(NULL) / (24*60*60);
osWrite(fh,STATS_IDENTIFIER,4);
osWrite(fh,&DayStatsWritten,sizeof(uint32_t));
osWrite(fh,&areas,sizeof(uint32_t));
for(area=(struct Area *)config.AreaList.First;area;area=area->Next)
{
if(area->AreaType == AREATYPE_BAD || area->AreaType == AREATYPE_ECHOMAIL || area->AreaType == AREATYPE_NETMAIL)
{
if(!(area->Flags & AREA_UNCONFIRMED))
{
strcpy(dastat.Tagname,area->Tagname);
dastat.TotalTexts=area->Texts;
dastat.Dupes=area->Dupes;
dastat.LastTime=area->LastTime;
dastat.FirstTime=area->FirstTime;
memcpy(&dastat.Last8Days[0],&area->Last8Days[0],sizeof(uint16_t)*8);
Copy4D(&dastat.Aka,&area->Aka->Node);
dastat.Group=area->Group;
osWrite(fh,&dastat,sizeof(struct DiskAreaStats));
}
}
}
osWrite(fh,&nodes,sizeof(uint32_t));
for(cnode=(struct ConfigNode *)config.CNodeList.First;cnode;cnode=cnode->Next)
{
Copy4D(&dnstat.Node,&cnode->Node);
dnstat.GotEchomails=cnode->GotEchomails;
dnstat.GotEchomailBytes=cnode->GotEchomailBytes;
dnstat.SentEchomails=cnode->SentEchomails;
dnstat.SentEchomailBytes=cnode->SentEchomailBytes;
dnstat.GotNetmails=cnode->GotNetmails;
dnstat.GotNetmailBytes=cnode->GotNetmailBytes;
dnstat.SentNetmails=cnode->SentNetmails;
dnstat.SentNetmailBytes=cnode->SentNetmailBytes;
dnstat.Dupes=cnode->Dupes;
dnstat.FirstTime=cnode->FirstTime;
osWrite(fh,&dnstat,sizeof(struct DiskNodeStats));
}
osClose(fh);
return(TRUE);
}
bool ReadStats(char *file)
{
struct Area *area;
struct ConfigNode *cnode;
struct DiskAreaStats dastat;
struct DiskNodeStats dnstat;
uint32_t c,num;
osFile fh;
char buf[5];
if(!(fh=osOpen(file,MODE_OLDFILE)))
return(TRUE); /* No reason for exiting */
osRead(fh,buf,4);
buf[4]=0;
if(strcmp(buf,STATS_IDENTIFIER)!=0)
{
LogWrite(1,SYSTEMERR,"Unknown format of stats file %s, exiting...",file);
osClose(fh);
return(FALSE);
}
osRead(fh,&DayStatsWritten,sizeof(uint32_t));
osRead(fh,&num,sizeof(uint32_t));
c=0;
while(c<num && osRead(fh,&dastat,sizeof(struct DiskAreaStats))==sizeof(struct DiskAreaStats))
{
for(area=(struct Area *)config.AreaList.First;area;area=area->Next)
if(stricmp(area->Tagname,dastat.Tagname)==0) break;
if(area)
{
area->Texts=dastat.TotalTexts;
area->Dupes=dastat.Dupes;
area->FirstTime=dastat.FirstTime;
area->LastTime=dastat.LastTime;
memcpy(&area->Last8Days[0],&dastat.Last8Days[0],sizeof(uint16_t)*8);
}
c++;
}
osRead(fh,&num,sizeof(uint32_t));
c=0;
while(c<num && osRead(fh,&dnstat,sizeof(struct DiskNodeStats))==sizeof(struct DiskNodeStats))
{
for(cnode=(struct ConfigNode *)config.CNodeList.First;cnode;cnode=cnode->Next)
if(Compare4D(&dnstat.Node,&cnode->Node)==0) break;
if(cnode)
{
cnode->GotEchomails=dnstat.GotEchomails;
cnode->GotEchomailBytes=dnstat.GotEchomailBytes;
cnode->SentEchomails=dnstat.SentEchomails;
cnode->SentEchomailBytes=dnstat.SentEchomailBytes;
cnode->GotNetmails=dnstat.GotNetmails;
cnode->GotNetmailBytes=dnstat.GotNetmailBytes;
cnode->SentNetmails=dnstat.SentNetmails;
cnode->SentNetmailBytes=dnstat.SentNetmailBytes;
cnode->Dupes=dnstat.Dupes;
cnode->FirstTime=dnstat.FirstTime;
}
c++;
}
osClose(fh);
return(TRUE);
}

View File

@ -0,0 +1,2 @@
bool ReadStats(char *file);
bool WriteStats(char *file);

View File

@ -0,0 +1,326 @@
#include "magimail.h"
bool Compare(char *str,char *recog)
{
uint32_t c,d;
char comp;
char buf[5];
d=0;
for(c=0;d<strlen(recog);c++)
{
if(recog[d]=='$')
{
strncpy(buf,&recog[d+1],2);
buf[2]=0;
comp=hextodec(buf);
if(str[c]!=comp) return(FALSE);
d+=3;
}
else
{
if(str[c]!=recog[d] && recog[d]!='?') return(FALSE);
d++;
}
}
return(TRUE);
}
struct Packer *DetectPacker(char *file)
{
osFile fh;
char buf[40];
struct Packer *tmppacker;
if(!(fh=osOpen(file,MODE_OLDFILE)))
{
uint32_t err=osError();
LogWrite(1,SYSTEMERR,"Unable to open %s",file);
LogWrite(1,SYSTEMERR,"Error: %s",osErrorMsg(err));
return(NULL);
}
osRead(fh,buf,40);
osClose(fh);
for(tmppacker=(struct Packer *)config.PackerList.First;tmppacker;tmppacker=tmppacker->Next)
if(Compare(buf,tmppacker->Recog)) return(tmppacker);
return(NULL);
}
void LogTossResults(void)
{
struct Area *area;
printf("\n");
for(area=(struct Area *)config.AreaList.First;area;area=area->Next)
{
if(ctrlc)
return;
if(area->NewDupes)
LogWrite(3,TOSSINGINFO,"Area %s -- %u messages (%u dupes)",area->Tagname,area->NewTexts,area->NewDupes);
else if(area->NewTexts)
LogWrite(3,TOSSINGINFO,"Area %s -- %u messages",area->Tagname,area->NewTexts);
}
printf("\n");
LogWrite(1,TOSSINGINFO," Total -> Read messages: %6lu Written messages: %6lu",toss_read,toss_written);
LogWrite(1,TOSSINGINFO,"Imported -> Imported messages: %6lu Routed netmails: %6lu",toss_import,toss_route);
LogWrite(1,TOSSINGINFO," Bad -> Bad messages: %6lu Duplicate messages: %6lu",toss_bad,toss_dupes);
printf("\n");
}
bool TossBundle(char *file,struct osFileEntry *fe)
{
struct Packer *tmppacker;
char buf[200],buf2[100];
struct jbList FEList;
struct osFileEntry *pktfe,*safedel;
int arcres;
if(fe->Size == 0)
{
LogWrite(1,TOSSINGINFO,"Deleting zero length bundle %s",file);
osDelete(file);
return(TRUE);
}
if(!(tmppacker=(struct Packer *)DetectPacker(file)))
{
LogWrite(1,TOSSINGINFO,"Failed to recognize archive type of %s",file);
BadFile(file,"Unknown packer");
return(TRUE);
}
printf("\n");
LogWrite(2,TOSSINGINFO,"Unarchiving %s using %s",file,tmppacker->Name);
printf("\n");
ExpandPacker(tmppacker->Unpacker,buf2,100,file,"");
arcres=osChDirExecute(config.cfg_TempDir,buf2);
printf("\n");
if(arcres == -1)
{
LogWrite(1,SYSTEMERR,"Unable to find temp directory \"%s\"",config.cfg_TempDir);
return(FALSE);
}
if(arcres!=0)
{
LogWrite(1,SYSTEMERR,"Unarchiving failed: %u",arcres);
sprintf(buf2,"Unarchiving with %s failed: %u",tmppacker->Name,arcres);
BadFile(file,buf2);
}
if(!osReadDir(config.cfg_TempDir,&FEList,IsPkt))
{
uint32_t err=osError();
LogWrite(1,SYSTEMERR,"Failed to read directory \"%s\"",config.cfg_TempDir);
LogWrite(1,SYSTEMERR,"Error: %s",osErrorMsg(err));
return(FALSE);
}
if(!SortFEList(&FEList))
{
jbFreeList(&FEList);
return(FALSE);
}
for(pktfe=(struct osFileEntry *)FEList.First;pktfe && !ctrlc;pktfe=pktfe->Next)
{
MakeFullPath(config.cfg_TempDir,pktfe->Name,buf,200);
/* If you have your tempdir in Inbound, this might be an unpacked
mailpacket that has been processed already */
for(safedel=(struct osFileEntry *)DeleteList.First;safedel;safedel=safedel->Next)
if(strcmp(safedel->Name,buf)==0) break;
if(!safedel)
{
if(!ReadPkt(buf,pktfe,TRUE,HandleMessage))
{
jbFreeList(&FEList);
return(FALSE);
}
osDelete(buf);
}
}
jbFreeList(&FEList);
if(ctrlc)
return(FALSE);
return(TRUE);
}
bool TossDir(char *dir)
{
struct osFileEntry *fe;
struct jbList PktFEList;
struct jbList ArcFEList;
char buf[200];
LogWrite(3,ACTIONINFO,"Tossing files in %s...",dir);
if(!BeforeScanToss())
return(FALSE);
/* Notify about old bad files */
if(!osReadDir(dir,&PktFEList,IsBad))
{
uint32_t err=osError();
LogWrite(1,SYSTEMERR,"Failed to read directory \"%s\"",dir);
LogWrite(1,SYSTEMERR,"Error: %s",osErrorMsg(err));
AfterScanToss(FALSE);
return(FALSE);
}
for(fe=(struct osFileEntry *)PktFEList.First;fe;fe=fe->Next)
LogWrite(1,TOSSINGINFO,"Old bad file found in inbound: %s",fe->Name);
jbFreeList(&PktFEList);
/* Search for pkt files */
if(!osReadDir(dir,&PktFEList,IsPkt))
{
uint32_t err=osError();
LogWrite(1,SYSTEMERR,"Failed to read directory \"%s\"",dir);
LogWrite(1,SYSTEMERR,"Error: %s",osErrorMsg(err));
AfterScanToss(FALSE);
return(FALSE);
}
/* Search for bundles */
if(!osReadDir(dir,&ArcFEList,IsArc))
{
uint32_t err=osError();
LogWrite(1,SYSTEMERR,"Failed to read directory \"%s\"",dir);
LogWrite(1,SYSTEMERR,"Error: %s",osErrorMsg(err));
jbFreeList(&PktFEList);
AfterScanToss(FALSE);
return(FALSE);
}
SortFEList(&PktFEList);
SortFEList(&ArcFEList);
if(nomem)
{
jbFreeList(&PktFEList);
jbFreeList(&ArcFEList);
AfterScanToss(FALSE);
return(FALSE);
}
/* Process pkt files */
for(fe=(struct osFileEntry *)PktFEList.First;fe && !ctrlc;fe=fe->Next)
{
MakeFullPath(dir,fe->Name,buf,200);
if(!ReadPkt(buf,fe,FALSE,HandleMessage))
{
jbFreeList(&PktFEList);
jbFreeList(&ArcFEList);
AfterScanToss(FALSE);
return(FALSE);
}
SafeDelete(buf);
}
for(fe=(struct osFileEntry *)ArcFEList.First;fe && !ctrlc;fe=fe->Next)
{
MakeFullPath(dir,fe->Name,buf,200);
if(!TossBundle(buf,fe))
{
jbFreeList(&PktFEList);
jbFreeList(&ArcFEList);
AfterScanToss(FALSE);
return(FALSE);
}
SafeDelete(buf);
}
jbFreeList(&PktFEList);
jbFreeList(&ArcFEList);
if(ctrlc)
{
AfterScanToss(FALSE);
return(FALSE);
}
LogTossResults();
AfterScanToss(TRUE);
return(TRUE);
}
bool TossFile(char *file)
{
struct osFileEntry *fe;
LogWrite(3,ACTIONINFO,"Tossing file %s...",file);
if(!(fe=osGetFileEntry(file)))
{
uint32_t err=osError();
LogWrite(1,SYSTEMERR,"Failed to read file \"%s\"",file);
LogWrite(1,SYSTEMERR,"Error: %s",osErrorMsg(err));
return(FALSE);
}
if(!BeforeScanToss())
{
osFree(fe);
return(FALSE);
}
if(IsPkt(fe->Name))
{
if(!ReadPkt(file,fe,FALSE,HandleMessage))
{
osFree(fe);
AfterScanToss(FALSE);
return(FALSE);
}
SafeDelete(file);
}
else
{
if(!TossBundle(file,fe))
{
osFree(fe);
AfterScanToss(FALSE);
return(FALSE);
}
SafeDelete(file);
}
LogTossResults();
AfterScanToss(TRUE);
return(TRUE);
}

View File

@ -0,0 +1,3 @@
bool TossFile(char *file);
bool TossDir(char *dir);

View File

@ -0,0 +1,13 @@
#ifndef VERSION_H
#define VERSION_H
#define VERSION_MAJOR 1
#define VERSION_MINOR 0
#define VERSION_PATCH 0
#define VERSION "1.0"
#define TID_VERSION "1.0"
#endif /* VERSION_H */

View File

@ -0,0 +1,20 @@
#ifndef OS_OS_H
#define OS_OS_H
#include <shared/types.h>
bool osInit(void);
void osEnd(void);
#if defined(PLATFORM_WIN32)
#include <oslib_win32/os_win32.h>
#elif defined(PLATFORM_LINUX)
#include <oslib_linux/os_linux.h>
#elif defined(PLATFORM_OS2)
#include <oslib_os2/os_os2.h>
#else
#error Unsupported platform
#endif
#endif

View File

@ -0,0 +1,20 @@
#ifndef OS_OSDIR_H
#define OS_OSDIR_H
#include "shared/types.h"
#include <time.h>
struct osFileEntry
{
struct osFileEntry *Next;
char Name[100];
time_t Date;
uint32_t Size;
};
bool osReadDir(char *dir,struct jbList *filelist,bool (*acceptfunc)(char *filename));
bool osScanDir(char *dir,void (*func)(char *file));
struct osFileEntry *osGetFileEntry(char *file);
#endif

View File

@ -0,0 +1,30 @@
#ifndef OS_OSFILE_H
#define OS_OSFILE_H
#include <stdarg.h>
#include "shared/types.h"
typedef void *osFile;
#define MODE_OLDFILE 1005 /* Corresponds to "rb" with fopen */
#define MODE_NEWFILE 1006 /* Corresponds to "wb" with fopen */
#define MODE_READWRITE 1004 /* Corresponds to "w+b" with fopen */
#define OFFSET_BEGINNING -1
#define OFFSET_END 1
osFile osOpen(char *name,uint32_t mode);
void osClose(osFile os);
int osGetChar(osFile os);
uint32_t osRead(osFile os,void *buf,uint32_t bytes);
uint32_t osFGets(osFile os,char *str,uint32_t max);
off_t osFTell(osFile os);
bool osPutChar(osFile os, char ch);
bool osWrite(osFile os,const void *buf, uint32_t bytes);
bool osPuts(osFile os,char *str);
bool osFPrintf(osFile os,char *fmt,...);
bool osVFPrintf(osFile os,char *fmt,va_list args);
void osSeek(osFile os,off_t offset,short mode);
#endif

View File

@ -0,0 +1,10 @@
#ifndef OS_OSMEM_H
#define OS_OSMEM_H
#include "shared/types.h"
void *osAlloc(uint32_t size);
void *osAllocCleared(uint32_t size);
void osFree(void *buf);
#endif

View File

@ -0,0 +1,21 @@
#ifndef OS_OSMISC_H
#define OS_OSMISC_H
#include "shared/types.h"
void osSetComment(char *file,char *comment);
bool osExists(char *file);
int osChDirExecute(char *dir,char *cmd);
int osExecute(char *cmd);
bool osRename(char *oldfile,char *newfile);
bool osDelete(char *file);
bool osMkDir(char *dir);
void osSleep(int secs);
uint32_t osError(void);
char *osErrorMsg(uint32_t errnum);
#endif

View File

@ -0,0 +1,10 @@
#ifndef OS_OSPATTERN_H
#define OS_OSPATTERN_H
#include "shared/types.h"
bool osCheckPattern(char *pattern);
bool osMatchPattern(char *pattern,char *str);
bool osIsPattern(char *pattern);
#endif

View File

@ -0,0 +1,34 @@
INCDIR = ../
CC = gcc $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) -Wall -I $(INCDIR) -DPLATFORM_LINUX -g
AR = ar -ru
RM = rm -f
OBJS = osfile.o osdir.o osmisc.o osmem.o ospattern.o os.o
oslib.a : $(OBJS)
$(AR) oslib.a $(OBJS)
# os
osfile.o : osfile.c
$(CC) -c osfile.c -o osfile.o
osmisc.o : osmisc.c
$(CC) -c osmisc.c -o osmisc.o
osdir.o : osdir.c
$(CC) -c osdir.c -o osdir.o
osmem.o : osmem.c
$(CC) -c osmem.c -o osmem.o
ospattern.o : ospattern.c
$(CC) -c ospattern.c -o ospattern.o
os.o : os.c
$(CC) -c os.c -o os.o
clean :
$(RM) *.o *.a

View File

@ -0,0 +1,13 @@
#include <stdio.h>
#include <oslib/os.h>
bool osInit(void)
{
return(TRUE);
}
void osEnd(void)
{
}

View File

@ -0,0 +1,33 @@
#include <stddef.h>
#include <stdint.h>
typedef uint16_t UINT16; /* Unsigned 16-bit integer */
#define OS_EXIT_ERROR 10
#define OS_EXIT_OK 0
#define OS_PLATFORM_NAME "Linux"
#define OS_PATH_CHARS "/"
#define OS_CURRENT_DIR "."
#define OS_CONFIG_NAME "crashmail.prefs"
#define OS_CONFIG_VAR "CMCONFIGFILE"
#define OS_HAS_SYSLOG
/*
OS_PATH_CHARS is used by MakeFullPath. If path doesn't end with one of these characters,
the first character will be appended to it.
Example:
OS_PATH_CHARS = "/:"
"inbound" + "file" --> "inbound/file"
"inbound/" + "file" --> "inbound/file"
"inbound:" + "file" --> "inbound/file"
*/
#define stricmp strcasecmp
#define strnicmp strncasecmp

View File

@ -0,0 +1,100 @@
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <stdarg.h>
#include <stdio.h>
#include <time.h>
#include <dirent.h>
#include <sys/stat.h>
#include <shared/types.h>
#include <shared/jblist.h>
#include <shared/mystrncpy.h>
#include <shared/path.h>
#include <oslib/osmem.h>
#include <oslib/osdir.h>
bool osReadDir(char *dirname,struct jbList *filelist,bool (*acceptfunc)(char *filename))
{
DIR *dir;
struct dirent *dirent;
struct osFileEntry *tmp;
char buf[200];
jbNewList(filelist);
if(!(dir=opendir(dirname)))
return(FALSE);
while((dirent=readdir(dir)))
{
bool add;
if(!acceptfunc) add=TRUE;
else add=(*acceptfunc)(dirent->d_name);
if(add)
{
struct stat st;
MakeFullPath(dirname,dirent->d_name,buf,200);
if(stat(buf,&st) == 0)
{
if(!(tmp=(struct osFileEntry *)osAllocCleared(sizeof(struct osFileEntry))))
{
jbFreeList(filelist);
closedir(dir);
return(FALSE);
}
mystrncpy(tmp->Name,dirent->d_name,100);
tmp->Size=st.st_size;
tmp->Date=st.st_mtime;
jbAddNode(filelist,(struct jbNode *)tmp);
}
}
}
closedir(dir);
return(TRUE);
}
bool osScanDir(char *dirname,void (*func)(char *file))
{
DIR *dir;
struct dirent *dirent;
if(!(dir=opendir(dirname)))
return(FALSE);
while((dirent=readdir(dir)))
(*func)(dirent->d_name);
closedir(dir);
return(TRUE);
}
struct osFileEntry *osGetFileEntry(char *file)
{
struct stat st;
struct osFileEntry *tmp;
if(stat(file,&st) != 0)
return(FALSE);
if(!(tmp=(struct osFileEntry *)osAllocCleared(sizeof(struct osFileEntry))))
return(FALSE);
mystrncpy(tmp->Name,GetFilePart(file),100);
tmp->Size=st.st_size;
tmp->Date=st.st_mtime;
return(tmp);
}

View File

@ -0,0 +1,143 @@
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <stdarg.h>
#include <stdio.h>
#include <shared/types.h>
#include <oslib/osfile.h>
osFile osOpen(char *name,uint32_t mode)
{
FILE *fh;
if(mode == MODE_NEWFILE)
{
fh=fopen(name,"wb");
}
else if(mode == MODE_OLDFILE)
{
fh=fopen(name,"rb");
}
else
{
if(!(fh=fopen(name,"r+b")))
fh=fopen(name,"w+b");
}
return (osFile) fh;
}
void osClose(osFile os)
{
fclose((FILE *)os);
}
int osGetChar(osFile os)
{
int c;
c=fgetc((FILE *)os);
if(c==EOF)
c=-1;
return(c);
}
uint32_t osRead(osFile os,void *buf,uint32_t bytes)
{
return fread(buf,1,bytes,(FILE *)os);
}
bool osPutChar(osFile os, char ch)
{
if(fputc(ch,(FILE *)os)==EOF)
return(FALSE);
return(TRUE);
}
bool osWrite(osFile os,const void *buf,uint32_t bytes)
{
if(fwrite(buf,1,bytes,(FILE *)os)!=bytes)
return(FALSE);
return(TRUE);
}
bool osPuts(osFile os,char *str)
{
if(fputs(str,(FILE *)os)==EOF)
return(FALSE);
return(TRUE);
}
uint32_t osFGets(osFile os,char *str,uint32_t max)
{
char *s;
s=fgets(str,max,(FILE *)os);
if(s)
{
if(strlen(s)>=2 && s[strlen(s)-1]==10 && s[strlen(s)-2]==13)
{
/* CRLF -> LF */
s[strlen(s)-2]=10;
s[strlen(s)-1]=0;
}
return (uint32_t)strlen(s);
}
return(0);
}
off_t osFTell(osFile os)
{
return ftello((FILE *)os);
}
bool osFPrintf(osFile os,char *fmt,...)
{
va_list args;
int res;
va_start(args, fmt);
res=vfprintf(os,fmt,args);
va_end(args);
if(!res)
return(FALSE);
return(TRUE);
}
bool osVFPrintf(osFile os,char *fmt,va_list args)
{
int res;
res=vfprintf(os,fmt,args);
if(!res)
return(FALSE);
return(TRUE);
}
void osSeek(osFile fh,off_t offset,short mode)
{
int md;
if(mode == OFFSET_BEGINNING)
md=SEEK_SET;
if(mode == OFFSET_END)
md=SEEK_END;
fseeko((FILE *)fh,offset,md);
}

View File

@ -0,0 +1,19 @@
#include <stdlib.h>
#include <stdint.h>
#include <oslib/osmem.h>
void *osAlloc(uint32_t size)
{
return malloc((size_t)size);
}
void *osAllocCleared(uint32_t size)
{
return calloc((size_t)size,1);
}
void osFree(void *buf)
{
free(buf);
}

View File

@ -0,0 +1,99 @@
#include <stdint.h>
#include <string.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <shared/types.h>
#include <shared/jblist.h>
#include <oslib/osmisc.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <unistd.h>
void osSetComment(char *file,char *comment)
{
/* Does not exist in this os */
}
/* Returns -1 if dir was not found and errorlevel otherwise */
int osChDirExecute(char *dir,char *cmd)
{
char olddir[300];
int res;
if(!getcwd(olddir,300))
return(-1);
if(chdir(dir) != 0)
return(-1);
res=osExecute(cmd);
chdir(olddir);
return(res);
}
int osExecute(char *cmd)
{
int res;
res=system(cmd);
return WEXITSTATUS(res);
}
bool osExists(char *file)
{
struct stat st;
if(stat(file,&st) == 0)
return(TRUE);
return(FALSE);
}
bool osMkDir(char *dir)
{
if(mkdir(dir,0777) != 0)
return(FALSE);
return(TRUE);
}
bool osRename(char *oldfile,char *newfile)
{
if(rename(oldfile,newfile) == 0)
return(TRUE);
return(FALSE);
}
bool osDelete(char *file)
{
if(remove(file) == 0)
return(TRUE);
return(FALSE);
}
void osSleep(int secs)
{
sleep(secs);
}
char *osErrorMsg(uint32_t errnum)
{
return (char *)strerror(errnum);
}
uint32_t osError(void)
{
return (uint32_t)errno;
}

View File

@ -0,0 +1,40 @@
#include <string.h>
#include <ctype.h>
#include <oslib/os.h>
#include <oslib/ospattern.h>
bool osCheckPattern(char *pattern)
{
return(TRUE);
}
bool osMatchPattern(char *pattern,char *str)
{
int c;
for(c=0;pattern[c];c++)
{
if(pattern[c]=='*')
return(TRUE);
if(str[c] == 0)
return(FALSE);
if(pattern[c]!='?' && tolower(pattern[c])!=tolower(str[c]))
return(FALSE);
}
if(str[c]!=0)
return(FALSE);
return(TRUE);
}
bool osIsPattern(char *pat)
{
if(strchr(pat,'?') || strchr(pat,'*'))
return(TRUE);
return(FALSE);
}

View File

@ -0,0 +1,423 @@
#include <stdlib.h>
#include <string.h>
#include "shared/types.h"
#include "shared/expr.h"
#include <oslib/os.h>
#include <oslib/osmem.h>
struct expr *expr_get(struct expr *expr,int *errpos,char **errstr)
{
int c,d,len,start;
bool hasnot,hasquote,stop;
struct expr *res;
hasnot=FALSE;
c=expr->parsepos;
/* Skip leading whitespace */
while(expr->buf[c]==' ')
c++;
/* Check for NOT */
if(strnicmp(&expr->buf[c],"NOT ",4)==0)
{
c+=4;
hasnot=TRUE;
}
/* Check if parentheses */
if(expr->buf[c]=='(')
{
int nump;
nump=1;
d=c+1;
while(nump!=0 && expr->buf[d]!=0)
{
if(expr->buf[d]=='(') nump++;
if(expr->buf[d]==')') nump--;
d++;
}
if(nump == 0)
{
start=c+1;
len=d-c-2;
if(!(res=osAlloc(sizeof(struct expr))))
{
*errpos=expr->offset;
*errstr="Out of memory";
return(NULL);
}
if(!(res->buf=osAlloc(len+10)))
{
osFree(res);
*errpos=expr->offset;
*errstr="Out of memory";
return(NULL);
}
res->parsepos=0;
res->offset=expr->offset+start;
res->buf[0]=0;
if(hasnot)
strcat(res->buf,"NOT ");
strncat(res->buf,&expr->buf[start],len);
expr->parsepos=d;
return(res);
}
else
{
*errpos=expr->offset+c;
*errstr="No matching parenthesis found";
return(NULL);
}
}
d=c;
stop=FALSE;
hasquote=FALSE;
while(!stop)
{
if(expr->buf[d] == 0)
stop=TRUE;
if(expr->buf[d] == ' ' && !hasquote)
stop=TRUE;
if(expr->buf[d] == '"' && hasquote)
stop=TRUE;
if(expr->buf[d] == '"')
hasquote=TRUE;
if(!stop)
d++;
}
if(expr->buf[d]=='"')
d++;
start=c;
len=d-c;
if(!(res=osAlloc(sizeof(struct expr))))
{
*errpos=expr->offset;
*errstr="Out of memory";
return(NULL);
}
if(!(res->buf=osAlloc(len+10)))
{
osFree(res);
*errpos=expr->offset;
*errstr="Out of memory";
return(NULL);
}
res->parsepos=0;
res->offset=expr->offset+start;
res->buf[0]=0;
if(hasnot)
strcat(res->buf,"NOT ");
strncat(res->buf,&expr->buf[start],len);
expr->parsepos=d;
return(res);
}
struct expr *expr_getrest(struct expr *expr,int *errpos,char **errstr)
{
int c,d,start,len;
struct expr *res;
c=expr->parsepos;
/* Skip leading whitespace */
while(expr->buf[c]==' ')
c++;
d=c;
while(expr->buf[d]!=0)
d++;
start=c;
len=d-c;
if(!(res=osAlloc(sizeof(struct expr))))
{
*errpos=expr->offset;
*errstr="Out of memory";
return(NULL);
}
if(!(res->buf=osAlloc(len+10)))
{
osFree(res);
*errpos=expr->offset;
*errstr="Out of memory";
return(NULL);
}
res->parsepos=0;
res->offset=expr->offset+start;
res->buf[0]=0;
strncat(res->buf,&expr->buf[start],len);
expr->parsepos=d;
return(res);
}
struct expr *expr_makeexpr(char *str)
{
struct expr *expr;
if(!(expr=osAllocCleared(sizeof(struct expr))))
{
return(NULL);
}
if(!(expr->buf=osAlloc(strlen(str)+1)))
{
osFree(expr);
return(NULL);
}
strcpy(expr->buf,str);
return(expr);
}
void expr_free(struct expr *expr)
{
osFree(expr->buf);
osFree(expr);
}
int expr_eval(struct expr *expr,int (*eval)(char *str,int *errpos,char **errstr),int *errpos,char **errstr)
{
struct expr *e1,*e2,*e3;
e1=expr_get(expr,errpos,errstr);
if(!e1)
{
return(-1);
}
e2=expr_get(expr,errpos,errstr);
if(!e2)
{
expr_free(e1);
return(-1);
}
e3=expr_getrest(expr,errpos,errstr);
if(!e3)
{
expr_free(e1);
expr_free(e2);
return(-1);
}
if(e2->buf[0] == 0)
{
/* Only one expression */
if(strcmp(e1->buf,expr->buf)==0)
{
/* No more simplification possible */
if(strnicmp(e1->buf,"NOT ",4)==0)
{
int res;
strcpy(e1->buf,&e1->buf[4]);
e1->parsepos=0;
res=expr_eval(e1,eval,errpos,errstr);
if(res == 1) res=0;
else if(res == 0) res=1;
/* printf("NOT |%s|: %d\n",e1->buf,res); */
expr_free(e1);
expr_free(e2);
expr_free(e3);
return(res);
}
else
{
int res,tmperrpos;
res=(*eval)(e1->buf,&tmperrpos,errstr);
if(res == -1)
*errpos=e1->offset+tmperrpos;
/* printf("EVAL: |%s|: %d\n",e1->buf,res); */
expr_free(e1);
expr_free(e2);
expr_free(e3);
return(res);
}
}
else
{
int res;
res=expr_eval(e1,eval,errpos,errstr);
/* printf("|%s|: %d\n",e1->buf,res); */
expr_free(e1);
expr_free(e2);
expr_free(e3);
return (res);
}
}
if(stricmp(e2->buf,"AND")==0)
{
int r1,r2,res;
if(e3->buf[0] == 0)
{
*errstr="Expected second expression after AND";
*errpos=e3->offset;
expr_free(e1);
expr_free(e2);
expr_free(e3);
return(-1);
}
r1=expr_eval(e1,eval,errpos,errstr);
if(r1 == -1)
{
expr_free(e1);
expr_free(e2);
expr_free(e3);
return(-1);
}
r2=expr_eval(e3,eval,errpos,errstr);
if(r2 == -1)
{
expr_free(e1);
expr_free(e2);
expr_free(e3);
return(-1);
}
res=0;
if(r1 && r2)
res=1;
/* printf("|%s| AND |%s|: %d\n",e1->buf,e3->buf,res); */
expr_free(e1);
expr_free(e2);
expr_free(e3);
return(res);
}
else if(stricmp(e2->buf,"OR")==0)
{
int r1,r2,res;
if(e3->buf[0] == 0)
{
*errstr="Expected second expression after OR";
*errpos=e3->offset;
expr_free(e1);
expr_free(e2);
expr_free(e3);
return(-1);
}
r1=expr_eval(e1,eval,errpos,errstr);
if(r1 == -1)
{
expr_free(e1);
expr_free(e2);
expr_free(e3);
return(-1);
}
r2=expr_eval(e3,eval,errpos,errstr);
if(r2 == -1)
{
expr_free(e1);
expr_free(e2);
expr_free(e3);
return(-1);
}
res=0;
if(r1 || r2)
res=1;
/* printf("|%s| OR |%s|: %d\n",e1->buf,e3->buf,res); */
expr_free(e1);
expr_free(e2);
expr_free(e3);
return(res);
}
else
{
*errstr="Expected AND or OR";
*errpos=e2->offset;
expr_free(e1);
expr_free(e2);
expr_free(e3);
return(-1);
}
}

View File

@ -0,0 +1,11 @@
struct expr
{
char *buf;
int parsepos;
int offset;
};
int expr_eval(struct expr *expr,int (*eval)(char *str,int *errpos,char **errstr),int *errpos,char **errstr);
struct expr *expr_makeexpr(char *str);
void expr_free(struct expr *expr);

View File

@ -0,0 +1,92 @@
/* PktHeader */
#define PKTHEADER_ORIGNODE 0
#define PKTHEADER_DESTNODE 2
#define PKTHEADER_YEAR 4
#define PKTHEADER_MONTH 6
#define PKTHEADER_DAY 8
#define PKTHEADER_HOUR 10
#define PKTHEADER_MINUTE 12
#define PKTHEADER_SECOND 14
#define PKTHEADER_BAUD 16
#define PKTHEADER_PKTTYPE 18
#define PKTHEADER_ORIGNET 20
#define PKTHEADER_DESTNET 22
#define PKTHEADER_PRODCODELOW 24
#define PKTHEADER_REVMAJOR 25
#define PKTHEADER_PASSWORD 26
#define PKTHEADER_QORIGZONE 34
#define PKTHEADER_QDESTZONE 36
#define PKTHEADER_AUXNET 38
#define PKTHEADER_CWVALIDCOPY 40
#define PKTHEADER_PRODCODEHIGH 42
#define PKTHEADER_REVMINOR 43
#define PKTHEADER_CAPABILWORD 44
#define PKTHEADER_ORIGZONE 46
#define PKTHEADER_DESTZONE 48
#define PKTHEADER_ORIGPOINT 50
#define PKTHEADER_DESTPOINT 52
#define PKTHEADER_PRODDATA 54
#define SIZE_PKTHEADER 58
/* PktHeader FSC-0045 */
#define PKTHEADER45_ORIGNODE 0
#define PKTHEADER45_DESTNODE 2
#define PKTHEADER45_ORIGPOINT 4
#define PKTHEADER45_DESTPOINT 6
#define PKTHEADER45_RESERVED 8
#define PKTHEADER45_SUBVERSION 16
#define PKTHEADER45_VERSION 18
#define PKTHEADER45_ORIGNET 20
#define PKTHEADER45_DESTNET 22
#define PKTHEADER45_PRODCODE 24
#define PKTHEADER45_REVISION 25
#define PKTHEADER45_PASSWORD 26
#define PKTHEADER45_ORIGZONE 34
#define PKTHEADER45_DESTZONE 36
#define PKTHEADER45_ORIGDOMAIN 38
#define PKTHEADER45_DESTDOMAIN 46
#define PKTHEADER45_PRODDATA 54
#define SIZE_PKTHEADER45 58
/* PktMsgHeader */
#define PKTMSGHEADER_PKTTYPE 0
#define PKTMSGHEADER_ORIGNODE 2
#define PKTMSGHEADER_DESTNODE 4
#define PKTMSGHEADER_ORIGNET 6
#define PKTMSGHEADER_DESTNET 8
#define PKTMSGHEADER_ATTR 10
#define PKTMSGHEADER_COST 12
/* plus header strings */
#define SIZE_PKTMSGHEADER 14
/* Header flags */
#define FLAG_PVT 1
#define FLAG_CRASH 2
#define FLAG_RECD 4
#define FLAG_SENT 8
#define FLAG_FILEATTACH 16
#define FLAG_INTRANSIT 32
#define FLAG_ORPHAN 64
#define FLAG_KILLSENT 128
#define FLAG_LOCAL 256
#define FLAG_HOLD 512
/* FLAG_UNUSED 1024 */
#define FLAG_FILEREQ 2048
#define FLAG_RREQ 4096
#define FLAG_IRRR 8192
#define FLAG_AUDIT 16384
#define FLAG_UPDATEREQ 32768

View File

@ -0,0 +1,96 @@
#include <stdlib.h>
#include <stddef.h>
#include <stdint.h>
#include "oslib/osmem.h"
#include "shared/jblist.h"
void jbNewList(struct jbList *list)
{
list->First=NULL;
list->Last=NULL;
}
void jbAddNode(struct jbList *list, struct jbNode *node)
{
if(!list->First)
list->First=node;
else
list->Last->Next=node;
list->Last=node;
node->Next=NULL;
}
void jbFreeList(struct jbList *list)
{
struct jbNode *tmp,*tmp2;
for(tmp=list->First;tmp;)
{
tmp2=tmp->Next;
osFree(tmp);
tmp=tmp2;
}
list->First=NULL;
list->Last=NULL;
}
void jbFreeNum(struct jbList *list,uint32_t num)
{
struct jbNode *old=NULL,*tmp;
uint32_t c;
tmp=list->First;
for(c=0;c<num && tmp;c++)
{
if(c==num-1)
old=tmp;
tmp=tmp->Next;
}
if(c==num)
{
if(old)
old->Next=tmp->Next;
if(num==0)
list->First=tmp->Next;
if(tmp->Next == NULL)
list->Last=old;
osFree(tmp);
}
}
void jbFreeNode(struct jbList *list,struct jbNode *node)
{
struct jbNode *old=NULL,*tmp;
for(tmp=list->First;tmp;tmp=tmp->Next)
{
if(tmp->Next == node)
old=tmp;
if(tmp == node) break;
}
if(tmp == node)
{
if(old)
old->Next=tmp->Next;
if(node == list->First)
list->First=tmp->Next;
if(tmp->Next == NULL)
list->Last=old;
osFree(tmp);
}
}

View File

@ -0,0 +1,21 @@
#ifndef SHARED_JBLIST_H
#define SHARED_JBLIST_H
struct jbList
{
struct jbNode *First;
struct jbNode *Last;
};
struct jbNode
{
struct jbNode *Next;
};
void jbAddNode(struct jbList *list, struct jbNode *node);
void jbNewList(struct jbList *list);
void jbFreeList(struct jbList *list);
void jbFreeNum(struct jbList *list,uint32_t num);
void jbFreeNode(struct jbList *list,struct jbNode *node);
#endif

View File

@ -0,0 +1,78 @@
#include <stdlib.h>
#include <stdint.h>
#include "shared/types.h"
bool jbstrcpy(char *dest,char *src,uint32_t maxlen,uint32_t *jbc)
{
uint32_t d=0;
uint32_t stopchar1,stopchar2;
uint32_t jbcpos;
jbcpos= *jbc;
while(src[jbcpos]==32 || src[jbcpos]==9) jbcpos++;
if(src[jbcpos]=='"')
{
jbcpos++;
stopchar1='"';
stopchar2=0;
}
else
{
stopchar1=' ';
stopchar2=9;
}
while(src[jbcpos]!=stopchar1 && src[jbcpos]!=stopchar2 && src[jbcpos]!=10 && src[jbcpos]!=0)
{
if(src[jbcpos]=='\\' && src[jbcpos+1]!=0 && src[jbcpos+1]!=10)
jbcpos++;
if(d<maxlen-1)
dest[d++]=src[jbcpos];
jbcpos++;
}
dest[d]=0;
if(src[jbcpos]==9 || src[jbcpos]==' ' || src[jbcpos]=='"')
jbcpos++;
*jbc=jbcpos;
if(d!=0 || stopchar1=='"')
return(TRUE);
return(FALSE);
}
bool jbstrcpyrest(char *dest,char *src,uint32_t maxlen,uint32_t *jbc)
{
uint32_t d=0;
uint32_t jbcpos;
jbcpos=*jbc;
while(src[jbcpos]==32 || src[jbcpos]==9)
jbcpos++;
while(src[jbcpos]!=10 && src[jbcpos]!=0)
{
if(d<maxlen-1)
dest[d++]=src[jbcpos];
jbcpos++;
}
dest[d]=0;
*jbc=jbcpos;
if(d!=0)
return(TRUE);
return(FALSE);
}

View File

@ -0,0 +1,7 @@
#ifndef SHARED_JBSTRCPY_H
#define SHARED_JBSTRCPY_H
bool jbstrcpy(char *dest,char *src,uint32_t maxlen,uint32_t *jbc);
bool jbstrcpyrest(char *dest,char *src,uint32_t maxlen,uint32_t *jbc);
#endif

View File

@ -0,0 +1,12 @@
#include <string.h>
#include <stdlib.h>
#include <stdint.h>
#include "shared/types.h"
void mystrncpy(char *dest,char *src,uint32_t len)
{
strncpy(dest,src,(size_t)len-1);
dest[len-1]=0;
}

View File

@ -0,0 +1,8 @@
#ifndef SHARED_MYSTRNCPY_H
#define SHARED_MYSTRNCPY_H
#include "shared/types.h"
void mystrncpy(char *dest,char *src,uint32_t len);
#endif

View File

@ -0,0 +1,100 @@
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <oslib/os.h>
#include "shared/parseargs.h"
bool parseargs(struct argument *arg,int argc, char **argv)
{
int i,j;
for(i=1;i<argc;i++)
{
for(j=0;arg[j].type;j++)
if(arg[j].name && stricmp(argv[i],arg[j].name)==0) break;
if(arg[j].type)
{
/* Matches a keyword */
if(arg[j].type == ARGTYPE_STRING)
{
if(i+1 < argc)
{
/* Has argument */
arg[j].data=(void *)argv[i+1];
i++;
}
else
{
/* Argument missing */
printf("No argument for %s\n",arg[j].name);
return(FALSE);
}
}
else if(arg[j].type == ARGTYPE_BOOL)
{
arg[j].data=(void *)TRUE;
}
}
else
{
/* Fill in first empty field */
for(j=0;arg[j].type;j++)
if((!arg[j].name || arg[j].flags & ARGFLAG_AUTO) && !arg[j].data) break;
if(!arg[j].type)
{
printf("Unknown keyword %s\n",argv[i]);
return(FALSE);
}
arg[j].data=(void *)argv[i];
}
}
for(j=0;arg[j].type;j++)
if((arg[j].flags & ARGFLAG_MANDATORY) && !arg[j].data)
{
printf("Mandatory argument %s not specified\n",arg[j].name);
return(FALSE);
}
return(TRUE);
}
void printargs(struct argument *arg)
{
int j;
char buf1[50],buf2[50];
printf("\nAvailable arguments:\n\n");
for(j=0;arg[j].type;j++)
if(arg[j].name)
{
if(arg[j].flags & ARGFLAG_AUTO) sprintf(buf1,"(%s)",arg[j].name);
else strcpy(buf1,arg[j].name);
buf2[0]=0;
if(arg[j].flags & ARGFLAG_MANDATORY) strcpy(buf2," [Mandatory]");
switch(arg[j].type)
{
case ARGTYPE_STRING:
printf("%s <string>%s\n",buf1,buf2);
break;
case ARGTYPE_BOOL:
printf("%s\n",arg[j].name);
break;
}
}
printf("\n");
printf("[Mandatory] means that the argument has to be specified. Parentheses around\n");
printf("the keyword mean that the keyword itself does not have to be specified.\n\n");
}

View File

@ -0,0 +1,24 @@
#ifndef SHARED_PARSEARGS_H
#define SHARED_PARSEARGS_H
#include "shared/types.h"
#define ARGTYPE_END 0
#define ARGTYPE_STRING 1
#define ARGTYPE_BOOL 2
#define ARGFLAG_AUTO 1 /* Keyword does not have to be specified */
#define ARGFLAG_MANDATORY 2 /* Argument cannot be left out */
struct argument
{
uint16_t type;
char *name;
uint16_t flags;
void *data;
};
bool parseargs(struct argument *arg,int argc, char **argv);
void printargs(struct argument *arg);
#endif

View File

@ -0,0 +1,57 @@
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <shared/types.h>
#include <shared/mystrncpy.h>
#include <oslib/os.h>
void MakeFullPath(char *path,char *file,char *dest,uint32_t destsize)
{
int d;
char *chr;
chr=OS_PATH_CHARS;
mystrncpy(dest,path,destsize);
d=strlen(dest);
if(d != 0)
{
if(!strchr(chr,dest[d-1]))
if(d+1 < destsize)
{
dest[d++]=(char)chr[0];
dest[d]=0;
}
}
if(destsize-d-1 > 0)
mystrncpy(&dest[d],file,destsize-d-1);
}
char *GetFilePart(char *str)
{
int d;
char *chr,*ret;
chr=OS_PATH_CHARS;
ret=str;
for(d=0;str[d];d++)
if(strchr(chr,str[d])) ret = &str[d+1];
return(ret);
}

View File

@ -0,0 +1,5 @@
void MakeFullPath(char *path,char *file,char *dest,uint32_t destsize);
char *GetFilePart(char *str);

View File

@ -0,0 +1,21 @@
struct StoredMsg
{
char From[36];
char To[36];
char Subject[72];
char DateTime[20];
UINT16 TimesRead;
UINT16 DestNode;
UINT16 OrigNode;
UINT16 Cost;
UINT16 OrigNet;
UINT16 DestNet;
UINT16 DestZone;
UINT16 OrigZone;
UINT16 DestPoint;
UINT16 OrigPoint;
UINT16 ReplyTo;
UINT16 Attr;
UINT16 NextReply;
/* Text */
};

View File

@ -0,0 +1,11 @@
#ifndef SHARED_TYPES_H
#define SHARED_TYPES_H
#ifndef NO_TYPEDEF_BOOL
typedef int bool;
#endif
#define FALSE 0
#define TRUE 1
#endif

View File

@ -0,0 +1,358 @@
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <time.h>
#include <ctype.h>
#include <oslib/os.h>
#include <oslib/osfile.h>
#include <oslib/osmisc.h>
#include <shared/types.h>
#include <shared/jbstrcpy.h>
#include <shared/parseargs.h>
#include <shared/node4d.h>
#include <magimail/version.h>
#ifdef PLATFORM_AMIGA
char *ver="$VER: CrashExport " VERSION " " __AMIGADATE__;
#endif
bool diskfull;
char cfgbuf[4000];
#define AREATYPE_NETMAIL 1
#define AREATYPE_ECHOMAIL 2
#define AREATYPE_DEFAULT 3
#define AREATYPE_BAD 4
#define AREATYPE_LOCAL 5
char tagname[100],desc[100],msgbase[10],path[100],export[1000],aka[50];
char group,areatype;
bool unconfirmed;
#define ARG_PREFSFILE 0
#define ARG_OUTFILE 1
#define ARG_FORMAT 2
#define ARG_GROUP 3
struct argument args[] =
{ { ARGTYPE_STRING, "PREFSFILE", ARGFLAG_AUTO | ARGFLAG_MANDATORY, NULL },
{ ARGTYPE_STRING, "OUTFILE", ARGFLAG_AUTO | ARGFLAG_MANDATORY, NULL },
{ ARGTYPE_STRING, "FORMAT", ARGFLAG_AUTO | ARGFLAG_MANDATORY, NULL },
{ ARGTYPE_STRING, "GROUP", 0, NULL },
{ ARGTYPE_END, NULL, 0, 0 } };
#define FORMAT_AREASBBS 0
#define FORMAT_FORWARD 1
#define FORMAT_FORWARDNODESC 2
#define FORMAT_GOLDED 3
#define FORMAT_TIMED 4
int format;
bool CheckFlags(char group,char *node)
{
int c;
for(c=0;c<strlen(node);c++)
{
if(toupper(group)==toupper(node[c]))
return(TRUE);
}
return(FALSE);
}
void writearea(osFile fh)
{
int c;
char escdesc[100];
char *gedmsgbase,*gedtype,*gedflags;
char gedgroupbuf[10];
char *timflags,*timkeyword;
/* Never write unconfirmed areas to output file */
if(unconfirmed)
return;
/* Never write default areas to output file */
if(areatype == AREATYPE_DEFAULT)
return;
/* Only write if in the right group */
if(args[ARG_GROUP].data && !CheckFlags(group,args[ARG_GROUP].data))
return;
/* Escape description */
strcpy(escdesc,desc);
for(c=0;escdesc[c];c++) /* Desc can't contain " */
if(escdesc[c] == '\"') escdesc[c]='\'';
switch(format)
{
case FORMAT_AREASBBS:
if(areatype != AREATYPE_NETMAIL && areatype != AREATYPE_LOCAL) /* Don't write netmail areas */
{
if(stricmp(msgbase,"MSG")==0) osFPrintf(fh,"%s %s %s\n",path,tagname,export);
else if(stricmp(msgbase,"JAM")==0) osFPrintf(fh,"!%s %s %s\n",path,tagname,export);
else if(stricmp(msgbase,"")==0) osFPrintf(fh,"#%s %s %s\n",tagname,tagname,export);
else osFPrintf(fh,"%s:%s %s %s\n",msgbase,path,tagname,export);
}
break;
case FORMAT_FORWARD: /* Don't write netmail, local or BAD areas */
if(areatype == AREATYPE_ECHOMAIL)
{
if(desc[0]) osFPrintf(fh,"%s %s\n",tagname,desc);
else osFPrintf(fh,"%s\n",tagname);
}
break;
case FORMAT_FORWARDNODESC: /* Don't write netmail or BAD areas */
if(areatype == AREATYPE_ECHOMAIL)
{
osFPrintf(fh,"%s\n",tagname);
}
break;
case FORMAT_GOLDED:
if(path[0]) /* Don't write pass-through areas */
{
if(stricmp(msgbase,"MSG")==0) gedmsgbase="FTS1";
else if(stricmp(msgbase,"JAM")==0) gedmsgbase="JAM";
else return;
if(areatype == AREATYPE_NETMAIL) gedtype="NET";
else if(areatype == AREATYPE_LOCAL) gedtype="LOCAL";
else gedtype="ECHO";
if(areatype == AREATYPE_NETMAIL) gedflags="(Loc Pvt)";
else gedflags="(Loc)";
if(group) sprintf(gedgroupbuf,"%c",group);
else strcpy(gedgroupbuf,"0");
osFPrintf(fh,"AREADEF %s \"%s\" %s %s %s %s %s %s\n",tagname,escdesc,gedgroupbuf,gedtype,gedmsgbase,path,aka,gedflags);
}
break;
case FORMAT_TIMED:
if(path[0]) /* Don't write pass-through areas */
{
if(stricmp(msgbase,"MSG")==0) timflags="";
else if(stricmp(msgbase,"JAM")==0) timflags=" -J";
else return;
if(areatype == AREATYPE_NETMAIL) timkeyword="NetArea";
else if(areatype == AREATYPE_LOCAL) timkeyword="LocalArea";
else timkeyword="EchoArea";
osFPrintf(fh,"%s \"%s\" %s %s -P%s%s\n",timkeyword,escdesc,tagname,path,aka,timflags);
}
break;
}
}
int main(int argc, char **argv)
{
osFile ifh,ofh;
char sysopname[100],cfgword[30],buf[100];
uint32_t jbcpos;
time_t t;
if(!osInit())
exit(OS_EXIT_ERROR);
if(argc > 1 &&
(strcmp(argv[1],"?")==0 ||
strcmp(argv[1],"-h")==0 ||
strcmp(argv[1],"--help")==0 ||
strcmp(argv[1],"help")==0 ||
strcmp(argv[1],"/h")==0 ||
strcmp(argv[1],"/?")==0 ))
{
printargs(args);
osEnd();
exit(OS_EXIT_OK);
}
if(!parseargs(args,argc,argv))
{
osEnd();
exit(OS_EXIT_ERROR);
}
if(stricmp((char *)args[ARG_FORMAT].data,"areasbbs")==0)
{
format=FORMAT_AREASBBS;
}
else if(stricmp((char *)args[ARG_FORMAT].data,"forward")==0)
{
format=FORMAT_FORWARD;
}
else if(stricmp((char *)args[ARG_FORMAT].data,"forwardnodesc")==0)
{
format=FORMAT_FORWARDNODESC;
}
else if(stricmp((char *)args[ARG_FORMAT].data,"golded")==0)
{
format=FORMAT_GOLDED;
}
else if(stricmp((char *)args[ARG_FORMAT].data,"timed")==0)
{
format=FORMAT_TIMED;
}
else
{
printf("Unknown format \"%s\"\n",(char *)args[ARG_FORMAT].data);
osEnd();
exit(OS_EXIT_ERROR);
}
if(!(ifh=osOpen(args[ARG_PREFSFILE].data,MODE_OLDFILE)))
{
uint32_t err=osError();
printf("Failed to open %s for reading\n",(char *)args[ARG_PREFSFILE].data);
printf("Error: %s",osErrorMsg(err));
osEnd();
exit(OS_EXIT_ERROR);
}
if(!(ofh=osOpen(args[ARG_OUTFILE].data,MODE_NEWFILE)))
{
uint32_t err=osError();
printf("Failed to open %s for writing\n",(char *)args[ARG_OUTFILE].data);
printf("Error: %s",osErrorMsg(err));
osClose(ifh);
osEnd();
exit(OS_EXIT_ERROR);
}
time(&t);
osFPrintf(ofh,"; Generated by CrashExport %s\n; %s\n",VERSION,ctime(&t));
if(format == FORMAT_AREASBBS)
{
/* Get default origin and sysop name for areas.bbs */
strcpy(sysopname,"Sysop");
while(osFGets(ifh,cfgbuf,4000))
{
jbcpos=0;
jbstrcpy(cfgword,cfgbuf,30,&jbcpos);
if(stricmp(cfgword,"SYSOP")==0)
jbstrcpy(sysopname,cfgbuf,100,&jbcpos);
}
osFPrintf(ofh,"%s ! %s\n","Default origin",sysopname);
osSeek(ifh,0,OFFSET_BEGINNING);
}
while(osFGets(ifh,cfgbuf,4000))
{
jbcpos=0;
jbstrcpy(cfgword,cfgbuf,30,&jbcpos);
if(stricmp(cfgword,"AREA")==0 || stricmp(cfgword,"NETMAIL")==0 || stricmp(cfgword,"LOCALAREA")==0)
{
if(tagname[0])
writearea(ofh);
group=0;
unconfirmed=FALSE;
export[0]=0;
desc[0]=0;
jbstrcpy(tagname,cfgbuf,100,&jbcpos);
jbstrcpy(aka,cfgbuf,50,&jbcpos);
jbstrcpy(msgbase,cfgbuf,10,&jbcpos);
jbstrcpy(path,cfgbuf,100,&jbcpos);
if(stricmp(cfgword,"NETMAIL")==0)
areatype=AREATYPE_NETMAIL;
else if(stricmp(cfgword,"LOCALAREA")==0)
areatype=AREATYPE_LOCAL;
else if(stricmp(tagname,"BAD")==0)
areatype=AREATYPE_BAD;
else if(stricmp(tagname,"DEFAULT")==0 || strnicmp(tagname,"DEFAULT_",8)==0)
areatype=AREATYPE_DEFAULT;
else
areatype=AREATYPE_ECHOMAIL;
}
if(stricmp(cfgword,"EXPORT")==0)
{
struct Node4D tpl4d,tmp4d;
tpl4d.Zone=0;
tpl4d.Net=0;
tpl4d.Node=0;
tpl4d.Point=0;
while(jbstrcpy(buf,cfgbuf,100,&jbcpos))
{
if(buf[0]=='!' || buf[0]=='%' || buf[0]=='@')
strcpy(buf,&buf[1]);
if(Parse4DTemplate(buf,&tmp4d,&tpl4d))
{
Copy4D(&tpl4d,&tmp4d);
tpl4d.Point=0;
Print4D(&tmp4d,buf);
if(strlen(export) < sizeof(export)-20)
{
if(export[0]) strcat(export," ");
strcat(export,buf);
}
}
}
}
if(stricmp(cfgword,"UNCONFIRMED")==0)
{
unconfirmed=TRUE;
}
if(stricmp(cfgword,"DESCRIPTION")==0)
{
jbstrcpy(desc,cfgbuf,100,&jbcpos);
}
if(stricmp(cfgword,"GROUP")==0)
{
if(jbstrcpy(buf,cfgbuf,100,&jbcpos))
group=buf[0];
}
}
if(tagname[0])
writearea(ofh);
osClose(ofh);
osClose(ifh);
osEnd();
exit(OS_EXIT_OK);
}

View File

@ -0,0 +1,156 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <oslib/os.h>
#include <oslib/osfile.h>
#include <shared/parseargs.h>
#include <shared/node4d.h>
#include <cmnllib/cmnllib.h>
#include <magimail/version.h>
#ifdef PLATFORM_AMIGA
char *ver="$VER: CrashCompileNL " VERSION " " __AMIGADATE__;
#endif
#define ARG_NODE 0
#define ARG_DIRECTORY 1
struct argument args[] =
{ { ARGTYPE_STRING, "NODE", ARGFLAG_AUTO | ARGFLAG_MANDATORY, NULL },
{ ARGTYPE_STRING, "DIRECTORY", ARGFLAG_AUTO, NULL },
{ ARGTYPE_END, NULL, 0, 0 } };
bool nomem,diskfull;
void strip(char *str)
{ int c;
for(c=strlen(str)-1;str[c] < 33 && c>=0;c--) str[c]=0;
}
int main(int argc, char **argv)
{
osFile fh;
char line[200],*dir,*buf;
struct Node4D n4d;
struct cmnlIdx idx;
if(!osInit())
exit(OS_EXIT_ERROR);
if(argc > 1 &&
(strcmp(argv[1],"?")==0 ||
strcmp(argv[1],"-h")==0 ||
strcmp(argv[1],"--help")==0 ||
strcmp(argv[1],"help")==0 ||
strcmp(argv[1],"/h")==0 ||
strcmp(argv[1],"/?")==0 ))
{
printargs(args);
osEnd();
exit(OS_EXIT_OK);
}
if(!parseargs(args,argc,argv))
{
osEnd();
exit(OS_EXIT_ERROR);
}
if(args[ARG_DIRECTORY].data)
dir=(char *)args[ARG_DIRECTORY].data;
else
dir=getenv("CMNODELISTDIR");
if(!dir)
{
printf("No directory specified and CMNODELISTDIR not set\n");
osEnd();
exit(OS_EXIT_ERROR);
}
if(!Parse4D((char *)args[ARG_NODE].data,&n4d))
{
printf("Invalid node %s\n",(char *)args[ARG_NODE].data);
exit(OS_EXIT_ERROR);
}
if(!(fh=cmnlOpenNL(dir)))
{
printf("%s\n",cmnlLastError());
exit(OS_EXIT_ERROR);
}
idx.zone=n4d.Zone;
idx.net=n4d.Net;
idx.node=n4d.Node;
idx.point=n4d.Point;
if(!cmnlFindNL(fh,dir,&idx,line,200))
{
cmnlCloseNL(fh);
printf("%s\n",cmnlLastError());
exit(OS_EXIT_ERROR);
}
cmnlCloseNL(fh);
printf("Node %d:%d/%d.%d\n",idx.zone,idx.net,idx.node,idx.point);
printf("Region %d, Hub %d\n",idx.region,idx.hub);
strip(line);
if(line[0]==',')
{
buf="Node";
strtok(line,","); /* Skip number */
}
else
{
buf=strtok(line,",");
if(!buf) buf="";
strtok(NULL,","); /* Skip number */
}
printf("Node is listed as a %s\n",buf);
if((buf=strtok(NULL,",")))
{
printf("Name: %s\n",buf);
}
if((buf=strtok(NULL,",")))
{
printf("Location: %s\n",buf);
}
if((buf=strtok(NULL,",")))
{
printf("Sysop: %s\n",buf);
}
if((buf=strtok(NULL,",")))
{
printf("Phone: %s\n",buf);
}
if((buf=strtok(NULL,",")))
{
printf("Baud: %s\n",buf);
}
if((buf=strtok(NULL,"")))
{
printf("Flags: %s\n",buf);
}
osEnd();
exit(OS_EXIT_OK);
}

View File

@ -0,0 +1,341 @@
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <stdio.h>
#include <time.h>
#include <ctype.h>
#include <shared/types.h>
#include <shared/jbstrcpy.h>
#include <shared/parseargs.h>
#include <shared/jblist.h>
#include <shared/path.h>
#include <shared/mystrncpy.h>
#include <oslib/os.h>
#include <oslib/osmem.h>
#include <oslib/osfile.h>
#include <oslib/osdir.h>
#include <oslib/osmisc.h>
#include <magimail/version.h>
#ifdef PLATFORM_AMIGA
char *ver="$VER: CrashList " VERSION " " __AMIGADATE__;
#endif
#define ARG_DIRECTORY 0
struct argument args[] =
{ { ARGTYPE_STRING, "DIRECTORY", ARGFLAG_AUTO, NULL },
{ ARGTYPE_END, NULL, 0, 0 } };
struct idx
{
uint16_t zone,net,node,point,region,hub;
uint32_t offset;
};
bool nomem,diskfull;
void putuword(char *buf,uint32_t offset,uint16_t num)
{
buf[offset]=num%256;
buf[offset+1]=num/256;
}
void putulong(char *buf,uint32_t offset,uint32_t num)
{
buf[offset]=num%256;
buf[offset+1]=(num / 256) % 256;
buf[offset+2]=(num / 256 / 256) % 256;
buf[offset+3]=(num / 256 / 256 / 256) % 256;
}
void WriteIdx(osFile fh,struct idx *idx)
{
char binbuf[16];
putuword(binbuf,0,idx->zone);
putuword(binbuf,2,idx->net);
putuword(binbuf,4,idx->node);
putuword(binbuf,6,idx->point);
putuword(binbuf,8,idx->region);
putuword(binbuf,10,idx->hub);
putulong(binbuf,12,idx->offset);
osWrite(fh,binbuf,sizeof(binbuf));
}
char nlname[100];
char *findfile,*finddir;
time_t newest;
bool isnodelistending(char *name)
{
if(strlen(name)<4) return(FALSE);
if(name[strlen(name)-4]!='.') return(FALSE);
if(!isdigit(name[strlen(name)-3])) return(FALSE);
if(!isdigit(name[strlen(name)-2])) return(FALSE);
if(!isdigit(name[strlen(name)-1])) return(FALSE);
return(TRUE);
}
void scandirfunc(char *file)
{
char buf[500];
struct osFileEntry *fe;
if(isnodelistending(file))
{
if(strnicmp(file,findfile,strlen(file)-4)==0)
{
MakeFullPath(finddir,file,buf,500);
if((fe=osGetFileEntry(buf)))
{
if(nlname[0]==0 || newest < fe->Date)
{
mystrncpy(nlname,fe->Name,100);
newest=fe->Date;
}
osFree(fe);
}
}
}
}
bool FindList(char *dir,char *file,char *dest)
{
MakeFullPath(dir,file,dest,500);
if(osExists(dest))
return(TRUE);
nlname[0]=0;
newest=0;
findfile=file;
finddir=dir;
if(!osScanDir(dir,scandirfunc))
{
uint32_t err=osError();
printf("Failed to scan directory %s\n",dir);
printf("Error: %s\n",osErrorMsg(err));
return(FALSE);
}
if(nlname[0]==0)
{
printf("Found no nodelist matching %s in %s\n",file,dir);
return(FALSE);
}
MakeFullPath(dir,nlname,dest,500);
return(TRUE);
}
void ProcessList(char *dir,char *file,osFile ifh,uint16_t defzone)
{
struct idx idx;
char buf[500];
osFile nfh;
if(!FindList(dir,file,buf))
return;
if(!(nfh=osOpen(buf,MODE_OLDFILE)))
{
uint32_t err=osError();
printf("Failed to read %s\n",buf);
printf("Error: %s\n",osErrorMsg(err));
return;
}
strcpy(buf,(char *)GetFilePart(buf));
printf("Processing nodelist %s...\n",buf);
osWrite(ifh,buf,100);
idx.zone=defzone;
idx.net=0;
idx.node=0;
idx.point=0;
idx.region=0;
idx.hub=0;
idx.offset=0;
idx.offset=osFTell(nfh);
while(osFGets(nfh,buf,500))
{
if(strnicmp(buf,"Zone,",5)==0)
{
idx.zone=atoi(&buf[5]);
idx.region=0;
idx.net=idx.zone;
idx.hub=0;
idx.node=0;
idx.point=0;
WriteIdx(ifh,&idx);
}
if(strnicmp(buf,"Region,",7)==0)
{
idx.region=atoi(&buf[7]);
idx.net=idx.region;
idx.hub=0;
idx.node=0;
idx.point=0;
WriteIdx(ifh,&idx);
}
if(strnicmp(buf,"Host,",5)==0)
{
idx.net=atoi(&buf[5]);
idx.hub=0;
idx.node=0;
idx.point=0;
WriteIdx(ifh,&idx);
}
if(strnicmp(buf,"Hub,",4)==0)
{
idx.hub=atoi(&buf[4]);
idx.node=idx.hub;
idx.point=0;
WriteIdx(ifh,&idx);
}
if(strnicmp(buf,"Pvt,",4)==0)
{
idx.node=atoi(&buf[4]);
idx.point=0;
WriteIdx(ifh,&idx);
}
if(strnicmp(buf,"Hold,",5)==0)
{
idx.node=atoi(&buf[5]);
idx.point=0;
WriteIdx(ifh,&idx);
}
if(strnicmp(buf,",",1)==0)
{
idx.node=atoi(&buf[1]);
idx.point=0;
WriteIdx(ifh,&idx);
}
if(strnicmp(buf,"Point,",6)==0)
{
idx.point=atoi(&buf[6]);
WriteIdx(ifh,&idx);
}
idx.offset=osFTell(nfh);
}
idx.zone=0;
idx.region=0;
idx.net=0;
idx.hub=0;
idx.node=0;
idx.point=0;
idx.offset=0xffffffff;
WriteIdx(ifh,&idx);
}
int main(int argc, char **argv)
{
osFile lfh,ifh;
char *dir,buf[200],cfgbuf[200],file[100];
uint32_t jbcpos,zone;
if(!osInit())
exit(OS_EXIT_ERROR);
if(argc > 1 &&
(strcmp(argv[1],"?")==0 ||
strcmp(argv[1],"-h")==0 ||
strcmp(argv[1],"--help")==0 ||
strcmp(argv[1],"help")==0 ||
strcmp(argv[1],"/h")==0 ||
strcmp(argv[1],"/?")==0 ))
{
printargs(args);
osEnd();
exit(OS_EXIT_OK);
}
if(!parseargs(args,argc,argv))
{
osEnd();
exit(OS_EXIT_ERROR);
}
dir=OS_CURRENT_DIR;
if(args[ARG_DIRECTORY].data)
dir=(char *)args[ARG_DIRECTORY].data;
MakeFullPath(dir,"cmnodelist.prefs",buf,200);
if(!(lfh=osOpen(buf,MODE_OLDFILE)))
{
uint32_t err=osError();
printf("Failed to open %s for reading\n",buf);
printf("Error: %s\n",osErrorMsg(err));
osEnd();
exit(OS_EXIT_ERROR);
}
MakeFullPath(dir,"cmnodelist.index",buf,200);
if(!(ifh=osOpen(buf,MODE_NEWFILE)))
{
uint32_t err=osError();
printf("Failed to open %s for writing (nodelist in use?)\n",buf);
printf("Error: %s\n",osErrorMsg(err));
osClose(lfh);
osEnd();
exit(OS_EXIT_ERROR);
}
osWrite(ifh,"CNL1",4);
while(osFGets(lfh,cfgbuf,200))
{
if(cfgbuf[0]!=';')
{
jbcpos=0;
if(jbstrcpy(file,cfgbuf,100,&jbcpos))
{
zone=0;
if(jbstrcpy(buf,cfgbuf,10,&jbcpos))
zone=atoi(buf);
ProcessList(dir,file,ifh,zone);
}
}
}
osClose(lfh);
osClose(ifh);
osEnd();
exit(OS_EXIT_OK);
}
/* Hitta rätt nodelista */

View File

@ -0,0 +1,726 @@
#include <string.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <ctype.h>
#include <shared/types.h>
#include <shared/mystrncpy.h>
#include <shared/path.h>
#include <shared/parseargs.h>
#include <shared/jblist.h>
#include <shared/node4d.h>
#include <oslib/os.h>
#include <oslib/osmem.h>
#include <oslib/osfile.h>
#include <oslib/osdir.h>
#include <oslib/osmisc.h>
#include <magimail/version.h>
#define NET(x) (x >> 16)
#define NODE(x) (x & 0xFFFF)
#define TYPE_CRASH 0
#define TYPE_DIRECT 1
#define TYPE_NORMAL 2
#define TYPE_HOLD 3
#define TYPE_REQUEST 4
char *type_names[] = { "Crash", "Direct", "Normal", "Hold", "Request" };
uint32_t TotalFiles=0;
uint32_t TotalBytes=0;
uint32_t TotalRequests=0;
struct fileentry
{
struct fileentry *Next;
struct Node4D Node;
char file[100];
char dir[100];
uint32_t size;
time_t date;
uint32_t type;
bool flow;
};
struct Node4DPat
{
char Zone[10];
char Net[10];
char Node[10];
char Point[10];
};
char *cfg_Dir;
uint32_t cfg_Zone;
struct Node4DPat cfg_Pattern;
bool cfg_Verbose;
#define ARG_DIRECTORY 0
#define ARG_ZONE 1
#define ARG_PATTERN 2
#define ARG_VERBOSE 3
struct argument args[] =
{ { ARGTYPE_STRING, "DIRECTORY", ARGFLAG_AUTO, NULL },
{ ARGTYPE_STRING, "ZONE", ARGFLAG_AUTO, NULL },
{ ARGTYPE_STRING, "PATTERN", ARGFLAG_AUTO, NULL },
{ ARGTYPE_BOOL, "VERBOSE", 0, NULL },
{ ARGTYPE_END, NULL, 0, 0 } };
struct jbList list;
/* Some stuff for node pattern (taken from MagiMail) */
bool Parse4DPat(char *buf, struct Node4DPat *node)
{
uint32_t c=0,tempc=0;
char temp[10];
bool GotZone=FALSE,GotNet=FALSE,GotNode=FALSE;
strcpy(node->Zone,"*");
strcpy(node->Net,"*");
strcpy(node->Node,"*");
strcpy(node->Point,"*");
if(strcmp(buf,"*")==0)
return(TRUE);
for(c=0;c<strlen(buf);c++)
{
if(buf[c]==':')
{
if(GotZone || GotNet || GotNode) return(FALSE);
strcpy(node->Zone,temp);
GotZone=TRUE;
tempc=0;
}
else if(buf[c]=='/')
{
if(GotNet || GotNode) return(FALSE);
strcpy(node->Net,temp);
GotNet=TRUE;
tempc=0;
}
else if(buf[c]=='.')
{
if(GotNode) return(FALSE);
strcpy(node->Node,temp);
node->Point[0]=0;
GotNode=TRUE;
tempc=0;
}
else if((buf[c]>='0' && buf[c]<='9') || buf[c]=='*' || buf[c]=='?')
{
if(tempc<9)
{
temp[tempc++]=buf[c];
temp[tempc]=0;
}
}
else return(FALSE);
}
if(GotZone && !GotNet)
{
strcpy(node->Net,temp);
}
else if(GotNode)
{
strcpy(node->Point,temp);
}
else
{
strcpy(node->Node,temp);
strcpy(node->Point,"0");
}
return(TRUE);
}
int NodeCompare(char *pat,uint16_t num)
{
char buf[10];
uint8_t c;
sprintf(buf,"%u",num);
if(pat[0]==0) return(0);
for(c=0;c<strlen(pat);c++)
{
if(pat[c]=='*') return(0);
if(pat[c]!=buf[c] && pat[c]!='?') return(1);
}
if(buf[c]!=0)
return(1);
return(0);
}
int Compare4DPat(struct Node4DPat *nodepat,struct Node4D *node)
{
if(node->Zone!=0)
if(NodeCompare(nodepat->Zone, node->Zone )!=0) return(1);
if(NodeCompare(nodepat->Net, node->Net )!=0) return(1);
if(NodeCompare(nodepat->Node, node->Node )!=0) return(1);
if(NodeCompare(nodepat->Point,node->Point)!=0) return(1);
return(0);
}
/* Some other functions from MagiMail */
char *unit(uint32_t i)
{
static char buf[20];
if ((i>10000000)||(i<-10000000)) sprintf(buf,"%uM",i/(1024*1024));
else if ((i>10000)||(i<-10000)) sprintf(buf,"%uK",i/1024);
else sprintf(buf,"%u",i);
return buf;
}
unsigned long hextodec(char *hex)
{
char *hextab="0123456789abcdef";
int c=0,c2=0;
unsigned long result=0;
for(;;)
{
for(c2=0;c2<16;c2++)
if(tolower(hex[c]) == hextab[c2]) break;
if(c2 == 16)
return(result); /* End of correct hex number */
result *= 16;
result += c2;
c++;
}
}
void strip(char *str)
{
int c;
for(c=strlen(str)-1;str[c] < 33 && c>=0;c--)
str[c]=0;
}
/* Display entries in the list */
char *PrintNode(struct Node4D *node)
{
static char buf[50];
Print4D(node,buf);
return(buf);
}
char *PrintDate(time_t date)
{
static char buf[50];
struct tm *tp;
char *monthnames[]={"Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec","???"};
tp=localtime(&date);
sprintf(buf,"%02d-%s-%02d %02d:%02d",
tp->tm_mday,
monthnames[tp->tm_mon],
tp->tm_year % 100,
tp->tm_hour,
tp->tm_min);
return(buf);
}
char *PrintFlowSize(struct fileentry *fe)
{
static char buf[50];
char fullfile[200],line[200];
osFile os;
struct osFileEntry *osfe;
uint32_t files,bytes;
files=0;
bytes=0;
MakeFullPath(cfg_Dir,fe->file,fullfile,200);
if(!(os=osOpen(fullfile,MODE_OLDFILE)))
{
sprintf(buf,"?/?");
return(buf);
}
while(osFGets(os,line,200))
{
strip(line);
if(line[0])
{
if(line[0] == '#' || line[0] == '^' || line[0] == '-')
strcpy(line,&line[1]);
if(stricmp(GetFilePart(line),line) == 0)
{
/* No path specified */
MakeFullPath(fe->dir,line,fullfile,200);
osfe=osGetFileEntry(fullfile);
}
else
{
osfe=osGetFileEntry(line);
}
if(osfe)
{
files++;
bytes+=osfe->Size;
TotalFiles++;
TotalBytes+=osfe->Size;
osFree(osfe);
}
}
}
osClose(os);
sprintf(buf,"%s/%u",unit(bytes),files);
return(buf);
}
void DisplayFlowContents(struct fileentry *fe)
{
char size[40],*todo;
char fullfile[200],line[200];
osFile os;
struct osFileEntry *osfe;
MakeFullPath(cfg_Dir,fe->file,fullfile,200);
if(!(os=osOpen(fullfile,MODE_OLDFILE)))
{
printf("Failed to open file\n");
}
else
{
while(osFGets(os,line,200))
{
strip(line);
if(line[0])
{
todo="";
if(line[0] == '#' || line[0] == '^') todo="(To be truncated)";
if(line[0] == '-') todo="(To be deleted)";
if(line[0] == '#' || line[0] == '^' || line[0] == '-')
strcpy(line,&line[1]);
if(stricmp(GetFilePart(line),line) == 0)
{
/* No path specified */
MakeFullPath(fe->dir,line,fullfile,200);
osfe=osGetFileEntry(fullfile);
}
else
{
osfe=osGetFileEntry(line);
}
strcpy(size,"Not found");
if(osfe)
{
sprintf(size, "%s", unit(osfe->Size));
osFree(osfe);
}
printf(" %-39.39s %10s %s\n",line,size,todo);
}
}
osClose(os);
}
printf("\n");
}
char *PrintReqNums(struct fileentry *fe)
{
static char buf[50];
char fullfile[200],line[200];
osFile os;
uint32_t reqs;
reqs=0;
MakeFullPath(cfg_Dir,fe->file,fullfile,200);
if(!(os=osOpen(fullfile,MODE_OLDFILE)))
{
sprintf(buf,"?/?");
return(buf);
}
while(osFGets(os,line,200))
{
strip(line);
if(line[0])
{
reqs++;
TotalRequests++;
}
}
sprintf(buf,"-/%u",reqs);
return(buf);
}
void DisplayReqContents(struct fileentry *fe)
{
char fullfile[200],line[200];
osFile os;
MakeFullPath(cfg_Dir,fe->file,fullfile,200);
if(!(os=osOpen(fullfile,MODE_OLDFILE)))
{
printf("Failed to open file\n");
}
else
{
while(osFGets(os,line,200))
{
strip(line);
if(line[0])
printf(" %s\n",line);
}
osClose(os);
}
printf("\n");
}
void DisplayFlow(struct fileentry *fe)
{
printf("%-8.8s %-17.17s %-16.16s %7.7s %s\n",
type_names[fe->type],PrintNode(&fe->Node),PrintDate(fe->date),PrintFlowSize(fe),fe->file);
if(cfg_Verbose)
DisplayFlowContents(fe);
}
void DisplayPkt(struct fileentry *fe)
{
char buf[100];
sprintf(buf,"%s/1",unit(fe->size));
printf("%-8.8s %-17.17s %-16.16s %7.7s %s\n",
type_names[fe->type],PrintNode(&fe->Node),PrintDate(fe->date),buf,fe->file);
if(cfg_Verbose)
printf("\n");
}
void DisplayReq(struct fileentry *fe)
{
printf("%-8.8s %-17.17s %-16.16s %7.7s %s\n",
type_names[fe->type],PrintNode(&fe->Node),PrintDate(fe->date),PrintReqNums(fe),fe->file);
if(cfg_Verbose)
DisplayReqContents(fe);
}
int sortcompare(const void *f1, const void *f2)
{
struct fileentry *e1,*e2;
e1=*(struct fileentry **)f1;
e2=*(struct fileentry **)f2;
return Compare4D(&e1->Node,&e2->Node);
}
void sortlist(struct jbList *list)
{
struct jbNode *jb,**buf,**work;
uint32_t count=0;
for(jb=list->First;jb;jb=jb->Next)
count++;
if(count < 2)
return;
if(!(buf=(struct jbNode **)osAlloc(count * sizeof(struct jbNode *))))
return;
work=buf;
for(jb=list->First;jb;jb=jb->Next)
*work++=jb;
qsort(buf,(size_t)count,(size_t)sizeof(struct jbNode *),sortcompare);
jbNewList(list);
for(work=buf;count--;)
jbAddNode(list,*work++);
osFree(buf);
}
void addentry(char *dir,char *file,uint32_t type,struct Node4D *boss,bool flow)
{
struct osFileEntry *fe;
struct fileentry *entry;
struct Node4D n4d;
char buf[200];
char buf2[200];
uint32_t hex;
hex=hextodec(file);
if(boss)
{
Copy4D(&n4d,boss);
n4d.Point = hex;
}
else
{
n4d.Zone = cfg_Zone;
n4d.Net = NET(hex);
n4d.Node = NODE(hex);
n4d.Point = 0;
}
if(Compare4DPat(&cfg_Pattern,&n4d)!=0)
return;
if(dir) MakeFullPath(dir,file,buf,200);
else mystrncpy(buf,file,200);
MakeFullPath(cfg_Dir,buf,buf2,200);
if(!(fe=osGetFileEntry(buf2)))
{
return;
}
if(!(entry=osAlloc(sizeof(struct fileentry))))
{
osFree(fe);
return;
}
Copy4D(&entry->Node,&n4d);
if(dir)
{
MakeFullPath(dir,file,entry->file,100);
MakeFullPath(cfg_Dir,dir,entry->dir,100);
}
else
{
mystrncpy(entry->file,file,100);
mystrncpy(entry->dir,cfg_Dir,100);
}
mystrncpy(entry->file,buf,100);
entry->size=fe->Size;
entry->date=fe->Date;
entry->type=type;
entry->flow=flow;
jbAddNode(&list,(struct jbNode *)entry);
osFree(fe);
}
struct Node4D *scandir_boss;
char *scandir_dir;
void scandirfunc(char *file)
{
char *extptr;
uint32_t hex;
if(strlen(file) != 12)
return;
extptr=&file[strlen(file)-4];
if(stricmp(extptr,".PNT")==0 && !scandir_boss)
{
char buf[200];
struct Node4D n4d;
hex=hextodec(file);
n4d.Zone = cfg_Zone;
n4d.Net = NET(hex);
n4d.Node = NODE(hex);
n4d.Point = 0;
scandir_dir = file;
scandir_boss = &n4d;
MakeFullPath(cfg_Dir,file,buf,200);
osScanDir(buf,scandirfunc);
scandir_dir = NULL;
scandir_boss = NULL;
}
if(!stricmp(extptr,".REQ")) addentry(scandir_dir,file,TYPE_REQUEST,scandir_boss,TRUE);
if(!stricmp(extptr,".CLO")) addentry(scandir_dir,file,TYPE_CRASH,scandir_boss,TRUE);
if(!stricmp(extptr,".DLO")) addentry(scandir_dir,file,TYPE_DIRECT,scandir_boss,TRUE);
if(!stricmp(extptr,".FLO")) addentry(scandir_dir,file,TYPE_NORMAL,scandir_boss,TRUE);
if(!stricmp(extptr,".HLO")) addentry(scandir_dir,file,TYPE_HOLD,scandir_boss,TRUE);
if(!stricmp(extptr,".CUT")) addentry(scandir_dir,file,TYPE_CRASH,scandir_boss,FALSE);
if(!stricmp(extptr,".DUT")) addentry(scandir_dir,file,TYPE_DIRECT,scandir_boss,FALSE);
if(!stricmp(extptr,".OUT")) addentry(scandir_dir,file,TYPE_NORMAL,scandir_boss,FALSE);
if(!stricmp(extptr,".HUT")) addentry(scandir_dir,file,TYPE_HOLD,scandir_boss,FALSE);
}
int main(int argc, char **argv)
{
char *var;
struct fileentry *fe;
if(!osInit())
exit(OS_EXIT_ERROR);
if(argc > 1 &&
(strcmp(argv[1],"?")==0 ||
strcmp(argv[1],"-h")==0 ||
strcmp(argv[1],"--help")==0 ||
strcmp(argv[1],"help")==0 ||
strcmp(argv[1],"/h")==0 ||
strcmp(argv[1],"/?")==0 ))
{
printargs(args);
osEnd();
exit(OS_EXIT_OK);
}
if(!parseargs(args,argc,argv))
{
osEnd();
exit(OS_EXIT_ERROR);
}
jbNewList(&list);
/* get outbound dir */
if((var=getenv("CMOUTBOUND")))
cfg_Dir=var;
else
cfg_Dir=OS_CURRENT_DIR;
if(args[ARG_DIRECTORY].data)
cfg_Dir=(char *)args[ARG_DIRECTORY].data;
/* Get zone */
if((var=getenv("CMOUTBOUNDZONE")))
cfg_Zone=atoi(var);
else
cfg_Zone=2;
if(args[ARG_ZONE].data)
cfg_Zone=atoi((char *)args[ARG_ZONE].data);
/* Get pattern */
strcpy(cfg_Pattern.Zone,"*");
strcpy(cfg_Pattern.Net,"*");
strcpy(cfg_Pattern.Node,"*");
strcpy(cfg_Pattern.Point,"*");
if(args[ARG_PATTERN].data)
{
if(!Parse4DPat((char *)args[ARG_PATTERN].data,&cfg_Pattern))
{
printf("Invalid node pattern \"%s\"\n",(char *)args[ARG_PATTERN].data);
osEnd();
exit(OS_EXIT_ERROR);
}
}
/* Get verbose flag */
cfg_Verbose=FALSE;
if(args[ARG_VERBOSE].data)
cfg_Verbose=TRUE;
/* Real program starts here */
printf("CrashListOut " VERSION "\n\n");
scandir_dir = NULL;
scandir_boss = NULL;
if(!osScanDir(cfg_Dir,scandirfunc))
{
uint32_t err=osError();
printf("Failed to scan directory %s\n",cfg_Dir);
printf("Error: %s",osErrorMsg(err));
return(FALSE);
}
sortlist(&list);
printf("%-8.8s %-17.17s %-16.16s %7.7s %s\n\n",
"Type","Node","Last Change","B/F","File");
if(list.First)
{
for(fe=(struct fileentry *)list.First;fe;fe=fe->Next)
{
if(fe->type == TYPE_REQUEST) DisplayReq(fe);
else if(fe->flow) DisplayFlow(fe);
else DisplayPkt(fe);
}
if(!cfg_Verbose) printf("\n");
printf("Totally %s bytes in %u files to send, %u requests.\n",unit(TotalBytes),TotalFiles,TotalRequests);
}
else
{
printf("Outbound directory is empty.\n");
}
jbFreeList(&list);
exit(OS_EXIT_OK);
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,707 @@
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <stdio.h>
#include <stdarg.h>
#include <time.h>
#include <signal.h>
#include <ctype.h>
#include <shared/types.h>
#include <shared/jblist.h>
#include <shared/parseargs.h>
#include <shared/node4d.h>
#include <oslib/os.h>
#include <oslib/osmem.h>
#include <oslib/osfile.h>
#include <oslib/osmisc.h>
#include <magimail/version.h>
#define COPYRIGHT "1998,2013"
#ifdef PLATFORM_AMIGA
char *ver="$VER: CrashStats "VERSION" ("__COMMODORE_DATE__")";
#endif
#define STATS_IDENTIFIER "CST3"
static size_t ptrsize = sizeof(void *);
struct DiskAreaStats
{
char Tagname[80];
struct Node4D Aka;
char Group;
char fill_to_make_even; /* Just ignore this one */
uint32_t TotalTexts;
uint16_t Last8Days[8];
uint32_t Dupes;
time_t FirstTime;
time_t LastTime;
};
struct DiskNodeStats
{
struct Node4D Node;
uint32_t GotNetmails;
uint32_t GotNetmailBytes;
uint32_t SentNetmails;
uint32_t SentNetmailBytes;
uint32_t GotEchomails;
uint32_t GotEchomailBytes;
uint32_t SentEchomails;
uint32_t SentEchomailBytes;
uint32_t Dupes;
time_t FirstTime;
};
struct StatsNode
{
struct StatsNode *Next;
char Tagname[80];
uint32_t Average;
uint32_t Total;
uint32_t Dupes;
time_t FirstTime;
time_t LastTime;
uint16_t Last8Days[8];
};
struct NodeStatsNode
{
struct NodeStatsNode *Next;
struct Node4D Node;
uint32_t GotNetmails;
uint32_t GotNetmailBytes;
uint32_t SentNetmails;
uint32_t SentNetmailBytes;
uint32_t GotEchomails;
uint32_t GotEchomailBytes;
uint32_t SentEchomails;
uint32_t SentEchomailBytes;
uint32_t Dupes;
uint32_t Days;
time_t FirstTime;
};
#define ARG_FILE 0
#define ARG_SORT 1
#define ARG_LAST7 2
#define ARG_NOAREAS 3
#define ARG_NONODES 4
#define ARG_GROUP 5
struct argument args[] =
{ { ARGTYPE_STRING, "FILE", ARGFLAG_AUTO | ARGFLAG_MANDATORY, NULL },
{ ARGTYPE_STRING, "SORT", 0, NULL },
{ ARGTYPE_BOOL, "LAST7", 0, NULL },
{ ARGTYPE_BOOL, "NOAREAS", 0, NULL },
{ ARGTYPE_BOOL, "NONODES", 0, NULL },
{ ARGTYPE_STRING, "GROUP", 0, NULL },
{ ARGTYPE_END, NULL, 0, 0 } };
bool diskfull;
int CompareAlpha(const void *a1,const void *a2)
{
struct StatsNode **s1,**s2;
s1=(struct StatsNode **)a1;
s2=(struct StatsNode **)a2;
return(stricmp((*s1)->Tagname,(*s2)->Tagname));
}
int CompareTotal(const void *a1,const void *a2)
{
struct StatsNode **s1,**s2;
s1=(struct StatsNode **)a1;
s2=(struct StatsNode **)a2;
if((*s1)->Total < (*s2)->Total) return(1);
if((*s1)->Total > (*s2)->Total) return(-1);
return(0);
}
int CompareDupes(const void *a1,const void *a2)
{
struct StatsNode **s1,**s2;
s1=(struct StatsNode **)a1;
s2=(struct StatsNode **)a2;
if((*s1)->Dupes < (*s2)->Dupes) return(1);
if((*s1)->Dupes > (*s2)->Dupes) return(-1);
return(0);
}
int CompareMsgsDay(const void *a1,const void *a2)
{
struct StatsNode **s1,**s2;
s1=(struct StatsNode **)a1;
s2=(struct StatsNode **)a2;
if((*s1)->Average < (*s2)->Average) return(1);
if((*s1)->Average > (*s2)->Average) return(-1);
return(0);
}
int CompareFirstTime(const void *a1,const void *a2)
{
struct StatsNode **s1,**s2;
s1=(struct StatsNode **)a1;
s2=(struct StatsNode **)a2;
if((*s1)->FirstTime < (*s2)->FirstTime) return(1);
if((*s1)->FirstTime > (*s2)->FirstTime) return(-1);
return(0);
}
int CompareLastTime(const void *a1,const void *a2)
{
struct StatsNode **s1,**s2;
s1=(struct StatsNode **)a1;
s2=(struct StatsNode **)a2;
if((*s1)->LastTime < (*s2)->LastTime) return(1);
if((*s1)->LastTime > (*s2)->LastTime) return(-1);
return(0);
}
bool Sort(struct jbList *list,char sortmode)
{
uint32_t nc;
struct StatsNode *sn,**buf,**work;
nc=0;
for(sn=(struct StatsNode *)list->First;sn;sn=sn->Next)
nc++;
if(nc==0)
return(TRUE); /* Nothing to sort */
if(!(buf=(struct StatsNode **)osAlloc(nc*sizeof(struct StatsNode *))))
return(FALSE);
work=buf;
for(sn=(struct StatsNode *)list->First;sn;sn=sn->Next)
*work++=sn;
switch(sortmode)
{
case 'a': qsort(buf,nc,ptrsize,CompareAlpha);
break;
case 't': qsort(buf,nc,ptrsize,CompareTotal);
break;
case 'm': qsort(buf,nc,ptrsize,CompareMsgsDay);
break;
case 'd': qsort(buf,nc,ptrsize,CompareFirstTime);
break;
case 'l': qsort(buf,nc,ptrsize,CompareLastTime);
break;
case 'u': qsort(buf,nc,ptrsize,CompareDupes);
break;
}
jbNewList(list);
for(work=buf;nc--;)
jbAddNode(list,(struct jbNode *)*work++);
osFree(buf);
return(TRUE);
}
int CompareNodes(const void *a1,const void *a2)
{
struct NodeStatsNode **s1,**s2;
s1=(struct NodeStatsNode **)a1;
s2=(struct NodeStatsNode **)a2;
return(Compare4D(&(*s1)->Node,&(*s2)->Node));
}
bool SortNodes(struct jbList *list)
{
struct NodeStatsNode *sn,**buf,**work;
uint32_t nc;
nc=0;
for(sn=(struct NodeStatsNode *)list->First;sn;sn=sn->Next)
nc++;
if(nc==0)
return(TRUE); /* Nothing to sort */
if(!(buf=(struct NodeStatsNode **)osAlloc(nc*sizeof(struct NodeStatsNode *))))
return(FALSE);
work=buf;
for(sn=(struct NodeStatsNode *)list->First;sn;sn=sn->Next)
*work++=sn;
qsort(buf,nc,ptrsize,CompareNodes);
jbNewList(list);
for(work=buf;nc--;)
jbAddNode(list,(struct jbNode *)*work++);
osFree(buf);
return(TRUE);
}
char *unit(uint32_t i)
{
static char buf[40];
if ((i>10000000)||(i<-10000000)) sprintf(buf,"%d MB",i/(1024*1024));
else if ((i>10000)||(i<-10000)) sprintf(buf,"%d KB",i/1024);
else sprintf(buf,"%d bytes",i);
return buf;
}
bool CheckFlags(char group,char *node)
{
int c;
for(c=0;c<strlen(node);c++)
{
if(toupper(group)==toupper(node[c]))
return(TRUE);
}
return(FALSE);
}
uint32_t CalculateAverage(uint16_t *last8array,uint32_t total,uint32_t daystatswritten,time_t firstday)
{
uint16_t days,c;
uint32_t sum;
if(daystatswritten == 0 || firstday == 0)
return(0);
days=daystatswritten-firstday;
if(days > 7) days=7;
sum=0;
for(c=1;c<days+1;c++)
sum+=last8array[c];
if(days == 0) days=1;
if(sum == 0 && total!=0)
{
days=daystatswritten-firstday;
if(days==0) days=1;
return(total/days);
}
return(sum/days);
}
bool ctrlc;
void breakfunc(int x)
{
ctrlc=TRUE;
}
int main(int argc, char **argv)
{
osFile fh;
uint32_t total,areas,totaldupes;
time_t firsttime,t;
uint32_t DayStatsWritten;
char buf[200],date[30],date2[30];
struct DiskAreaStats dastat;
struct DiskNodeStats dnstat;
struct StatsNode *sn;
struct NodeStatsNode *nsn;
struct jbList StatsList;
struct jbList NodesList;
uint32_t c,num,tot;
uint16_t total8days[8];
char sortmode;
struct tm *tp;
char *monthnames[]={"Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec","???"};
signal(SIGINT,breakfunc);
if(!osInit())
exit(OS_EXIT_ERROR);
if(argc > 1 &&
(strcmp(argv[1],"?")==0 ||
strcmp(argv[1],"-h")==0 ||
strcmp(argv[1],"--help")==0 ||
strcmp(argv[1],"help")==0 ||
strcmp(argv[1],"/h")==0 ||
strcmp(argv[1],"/?")==0 ))
{
printargs(args);
osEnd();
exit(OS_EXIT_OK);
}
if(!parseargs(args,argc,argv))
{
osEnd();
exit(OS_EXIT_ERROR);
}
sortmode='a';
if(args[ARG_SORT].data)
sortmode=tolower(((char *)args[ARG_SORT].data)[0]);
if(!strchr("amtdlu",sortmode))
{
printf("Unknown sort mode %c\n",sortmode);
osEnd();
exit(OS_EXIT_ERROR);
}
if(args[ARG_NOAREAS].data && args[ARG_NONODES].data)
{
printf("Nothing to do\n");
osEnd();
exit(OS_EXIT_ERROR);
}
printf("CrashStats "VERSION" © " COPYRIGHT " Johan Billing & Robert James Clay\n");
if(!(fh=osOpen(args[ARG_FILE].data,MODE_OLDFILE)))
{
uint32_t err=osError();
printf("Error opening %s\n",(char *)args[ARG_FILE].data);
printf("Error: %s\n",osErrorMsg(err));
osEnd();
exit(OS_EXIT_ERROR);
}
osRead(fh,buf,4);
buf[4]=0;
if(strcmp(buf,STATS_IDENTIFIER)!=0)
{
printf("Unknown format of stats file\n");
osClose(fh);
osEnd();
exit(OS_EXIT_ERROR);
}
osRead(fh,&DayStatsWritten,sizeof(uint32_t));
total=0;
totaldupes=0;
firsttime=0;
areas=0;
for(c=0;c<8;c++)
total8days[c]=0;
jbNewList(&StatsList);
jbNewList(&NodesList);
osRead(fh,&num,sizeof(uint32_t));
c=0;
if(!args[ARG_NOAREAS].data)
{
while(c<num && osRead(fh,&dastat,sizeof(struct DiskAreaStats))==sizeof(struct DiskAreaStats))
{
if(!args[ARG_GROUP].data || CheckFlags(dastat.Group,args[ARG_GROUP].data))
{
if(!(sn=osAlloc(sizeof(struct StatsNode))))
{
printf("Out of memory\n");
jbFreeList(&StatsList);
osClose(fh);
osEnd();
exit(OS_EXIT_ERROR);
}
jbAddNode(&StatsList,(struct jbNode *)sn);
strcpy(sn->Tagname,dastat.Tagname);
sn->Dupes=dastat.Dupes;
sn->Total=dastat.TotalTexts;
sn->FirstTime=dastat.FirstTime;
sn->LastTime=dastat.LastTime;
memcpy(&sn->Last8Days[0],&dastat.Last8Days[0],8*sizeof(uint16_t));
sn->Average=CalculateAverage(&dastat.Last8Days[0],dastat.TotalTexts,DayStatsWritten,sn->FirstTime / (24*60*60));
}
if(dastat.FirstTime!=0)
if(firsttime==0 || firsttime > dastat.FirstTime)
firsttime=dastat.FirstTime;
c++;
}
}
else
{
while(c<num && osRead(fh,&dastat,sizeof(struct DiskAreaStats))==sizeof(struct DiskAreaStats))
c++;
}
osRead(fh,&num,sizeof(uint32_t));
c=0;
if(!args[ARG_NONODES].data)
{
while(c<num && osRead(fh,&dnstat,sizeof(struct DiskNodeStats))==sizeof(struct DiskNodeStats))
{
if(!(nsn=osAlloc(sizeof(struct NodeStatsNode))))
{
printf("Out of memory\n");
jbFreeList(&NodesList);
jbFreeList(&StatsList);
osClose(fh);
osEnd();
exit(OS_EXIT_ERROR);
}
jbAddNode(&NodesList,(struct jbNode *)nsn);
Copy4D(&nsn->Node,&dnstat.Node);
nsn->GotNetmails=dnstat.GotNetmails;
nsn->GotNetmailBytes=dnstat.GotNetmailBytes;
nsn->SentNetmails=dnstat.SentNetmails;
nsn->SentNetmailBytes=dnstat.SentNetmailBytes;
nsn->GotEchomails=dnstat.GotEchomails;
nsn->GotEchomailBytes=dnstat.GotEchomailBytes;
nsn->SentEchomails=dnstat.SentEchomails;
nsn->SentEchomailBytes=dnstat.SentEchomailBytes;
nsn->Dupes=dnstat.Dupes;
nsn->Days=DayStatsWritten-dnstat.FirstTime % (24*60*60);
if(nsn->Days==0) nsn->Days=1;
nsn->FirstTime=dnstat.FirstTime;
if(dnstat.FirstTime!=0)
if(firsttime==0 || firsttime > dnstat.FirstTime)
firsttime=dnstat.FirstTime;
c++;
}
}
else
{
while(c<num && osRead(fh,&dnstat,sizeof(struct DiskNodeStats))==sizeof(struct DiskNodeStats))
c++;
}
osClose(fh);
t=(time_t)DayStatsWritten * 24*60*60;
tp=localtime(&firsttime);
sprintf(date,"%02d-%s-%02d",tp->tm_mday,monthnames[tp->tm_mon],tp->tm_year%100);
tp=localtime(&t);
sprintf(date2,"%02d-%s-%02d",tp->tm_mday,monthnames[tp->tm_mon],tp->tm_year%100);
printf("\nStatistics from %s to %s\n",date,date2);
if(!ctrlc && !args[ARG_NOAREAS].data)
{
Sort(&StatsList,'a');
Sort(&StatsList,sortmode);
printf("\n");
if(args[ARG_LAST7].data)
{
printf("Area ");
for(c=1;c<8;c++)
{
t=(DayStatsWritten-c)*24*60*60;
tp=localtime(&t);
printf(" %02d",tp->tm_mday);
}
printf(" Total\n============================================================================\n");
if(!ctrlc)
{
for(sn=(struct StatsNode *)StatsList.First;sn && !ctrlc;sn=sn->Next)
{
tot=0;
for(c=1;c<8;c++)
tot+=sn->Last8Days[c];
printf("%-33.33s %4d %4d %4d %4d %4d %4d %4d : %5d\n",
sn->Tagname,
sn->Last8Days[1],
sn->Last8Days[2],
sn->Last8Days[3],
sn->Last8Days[4],
sn->Last8Days[5],
sn->Last8Days[6],
sn->Last8Days[7],
tot);
for(c=1;c<8;c++)
total8days[c]+=sn->Last8Days[c];
areas++;
}
if(!ctrlc)
{
tot=0;
for(c=1;c<8;c++)
tot+=total8days[c];
printf("=============================================================================\n");
sprintf(buf,"Totally in all %u areas",areas);
printf("%-33.33s %4d %4d %4d %4d %4d %4d %4d : %5d\n",
buf,
total8days[1],
total8days[2],
total8days[3],
total8days[4],
total8days[5],
total8days[6],
total8days[7],
tot);
}
}
}
else
{
printf("Area First Last Msgs Msgs/day Dupes\n");
printf("============================================================================\n");
if(!ctrlc)
{
for(sn=(struct StatsNode *)StatsList.First;sn && !ctrlc;sn=sn->Next)
{
if(sn->LastTime==0)
{
strcpy(date2,"<Never>");
}
else
{
tp=localtime(&sn->LastTime);
sprintf(date2,"%02d-%s-%02d",tp->tm_mday,monthnames[tp->tm_mon],tp->tm_year%100);
}
if(sn->FirstTime==0)
{
strcpy(date,"<Never>");
}
else
{
tp=localtime(&sn->FirstTime);
sprintf(date,"%02d-%s-%02d",tp->tm_mday,monthnames[tp->tm_mon],tp->tm_year%100);
}
for(c=0;c<8;c++)
total8days[c]+=sn->Last8Days[c];
total+=sn->Total;
totaldupes+=sn->Dupes;
areas++;
printf("%-29.30s %-9.9s %-9.9s %7d %7d %7d\n",sn->Tagname,date,date2,sn->Total,sn->Average,sn->Dupes);
}
}
if(!ctrlc)
{
printf("============================================================================\n");
sprintf(buf,"Totally in all %u areas",areas);
printf("%-42s %7d %7d %7d\n",
buf,
total,
CalculateAverage(&total8days[0],total,DayStatsWritten,firsttime / (24*60*60)),
totaldupes);
}
}
}
if(!ctrlc && !args[ARG_NONODES].data)
{
SortNodes(&NodesList);
printf("\n");
printf("Nodes statistics\n");
printf("================\n");
for(nsn=(struct NodeStatsNode *)NodesList.First;nsn && !ctrlc;nsn=nsn->Next)
{
if(nsn->FirstTime==0)
{
strcpy(date,"<Never>");
}
else
{
tp=localtime(&nsn->FirstTime);
sprintf(date,"%0d-%s-%0d",tp->tm_mday,monthnames[tp->tm_mon],tp->tm_year%100);
}
sprintf(buf,"%u:%u/%u.%u",nsn->Node.Zone,nsn->Node.Net,nsn->Node.Node,nsn->Node.Point);
printf("%-30.40s Statistics since: %s\n\n",buf,date);
printf(" Sent netmails: %u/%s\n",nsn->SentNetmails,unit(nsn->SentNetmailBytes));
printf(" Received netmails: %u/%s\n",nsn->GotNetmails,unit(nsn->GotNetmailBytes));
printf(" Sent echomails: %u/%s\n",nsn->SentEchomails,unit(nsn->SentEchomailBytes));
printf(" Received echomails: %u/%s\n",nsn->GotEchomails,unit(nsn->GotEchomailBytes));
printf(" Dupes: %u\n",nsn->Dupes);
printf("\n");
}
}
if(ctrlc)
{
printf("*** Break\n");
}
else
{
printf("\n");
}
jbFreeList(&StatsList);
jbFreeList(&NodesList);
osEnd();
exit(OS_EXIT_OK);
}

View File

@ -0,0 +1,359 @@
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <stdio.h>
#include <signal.h>
#include <errno.h>
#include <time.h>
#include <shared/parseargs.h>
#include <shared/jbstrcpy.h>
#include <shared/path.h>
#include <shared/mystrncpy.h>
#include <shared/node4d.h>
#include <oslib/os.h>
#include <oslib/osfile.h>
#include <oslib/osmisc.h>
#include <shared/fidonet.h>
#include <magimail/version.h>
#ifdef PLATFORM_AMIGA
char *ver="$VER: CrashWrite "VERSION" ("__COMMODORE_DATE__")";
#endif
#define DEFAULT_TONAME "All"
#define DEFAULT_FROMNAME "CrashWrite"
#define DEFAULT_SUBJECT "Information"
#define DEFAULT_ORIGIN "Another user of MagiMail"
#define ARG_FROMNAME 0
#define ARG_FROMADDR 1
#define ARG_TONAME 2
#define ARG_TOADDR 3
#define ARG_SUBJECT 4
#define ARG_AREA 5
#define ARG_ORIGIN 6
#define ARG_DIR 7
#define ARG_TEXT 8
#define ARG_NOMSGID 9
#define ARG_FILEATTACH 10
#define ARG_PKTFROMADDR 11
#define ARG_PKTTOADDR 12
#define ARG_PASSWORD 13
struct argument args[] =
{ { ARGTYPE_STRING, "FROMNAME", 0, NULL },
{ ARGTYPE_STRING, "FROMADDR", 0, NULL },
{ ARGTYPE_STRING, "TONAME", 0, NULL },
{ ARGTYPE_STRING, "TOADDR", 0, NULL },
{ ARGTYPE_STRING, "SUBJECT", 0, NULL },
{ ARGTYPE_STRING, "AREA", 0, NULL },
{ ARGTYPE_STRING, "ORIGIN", 0, NULL },
{ ARGTYPE_STRING, "DIR", ARGFLAG_MANDATORY, NULL },
{ ARGTYPE_STRING, "TEXT", 0, NULL },
{ ARGTYPE_BOOL, "NOMSGID", 0, NULL },
{ ARGTYPE_BOOL, "FILEATTACH", 0, NULL },
{ ARGTYPE_STRING, "PKTFROMADDR", 0, NULL },
{ ARGTYPE_STRING, "PKTTOADDR", 0, NULL },
{ ARGTYPE_STRING, "PASSWORD", 0, NULL },
{ ARGTYPE_END, NULL, 0, 0 } };
char PktMsgHeader[SIZE_PKTMSGHEADER];
char PktHeader[SIZE_PKTHEADER];
bool nomem,diskfull;
uint16_t getuword(char *buf,uint32_t offset)
{
return (uint16_t)(buf[offset]+256*buf[offset+1]);
}
void putuword(char *buf,uint32_t offset,uint16_t num)
{
buf[offset]=num%256;
buf[offset+1]=num/256;
}
void MakeFidoDate(time_t tim,char *dest)
{
struct tm *tp;
time_t t;
char *monthnames[]={"Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec","???"};
t=tim;
tp=localtime(&t);
sprintf(dest,"%02d %s %02d %02d:%02d:%02d",
tp->tm_mday,
monthnames[tp->tm_mon],
tp->tm_year % 100,
tp->tm_hour,
tp->tm_min,
tp->tm_sec);
}
void WriteNull(osFile ofh,char *str)
{
osWrite(ofh,str,(uint32_t)(strlen(str)+1));
}
int main(int argc, char **argv)
{
struct Node4D from4d,to4d,pktfrom4d,pktto4d;
osFile ifh,ofh;
time_t t;
struct tm *tp;
uint32_t pktnum,c,serial;
uint16_t attr;
char fromname[36],toname[36],subject[72],datetime[20],origin[80];
char pktname[30],fullname[200],readbuf[100];
int i;
from4d.Zone=0;
from4d.Net=0;
from4d.Node=0;
from4d.Point=0;
to4d.Zone=0;
to4d.Net=0;
to4d.Node=0;
to4d.Point=0;
if(!osInit())
exit(OS_EXIT_ERROR);
if(argc > 1 &&
(strcmp(argv[1],"?")==0 ||
strcmp(argv[1],"-h")==0 ||
strcmp(argv[1],"--help")==0 ||
strcmp(argv[1],"help")==0 ||
strcmp(argv[1],"/h")==0 ||
strcmp(argv[1],"/?")==0 ))
{
printargs(args);
osEnd();
exit(OS_EXIT_OK);
}
if(!parseargs(args,argc,argv))
{
osEnd();
exit(OS_EXIT_ERROR);
}
if(args[ARG_FROMADDR].data)
{
if(!(Parse4D((char *)args[ARG_FROMADDR].data,&from4d)))
{
printf("Invalid address \"%s\"\n",(char *)args[ARG_FROMADDR].data);
osEnd();
exit(OS_EXIT_ERROR);
}
}
if(args[ARG_TOADDR].data)
{
if(!(Parse4D((char *)args[ARG_TOADDR].data,&to4d)))
{
printf("Invalid address \"%s\"\n",(char *)args[ARG_TOADDR].data);
osEnd();
exit(OS_EXIT_ERROR);
}
}
Copy4D(&pktfrom4d,&from4d);
Copy4D(&pktto4d,&to4d);
if(args[ARG_PKTFROMADDR].data)
{
if(!(Parse4D((char *)args[ARG_PKTFROMADDR].data,&pktfrom4d)))
{
printf("Invalid address \"%s\"\n",(char *)args[ARG_PKTFROMADDR].data);
osEnd();
exit(OS_EXIT_ERROR);
}
}
if(args[ARG_PKTTOADDR].data)
{
if(!(Parse4D((char *)args[ARG_PKTTOADDR].data,&pktto4d)))
{
printf("Invalid address \"%s\"\n",(char *)args[ARG_PKTTOADDR].data);
osEnd();
exit(OS_EXIT_ERROR);
}
}
time(&t);
tp=localtime(&t);
/* Create packet header */
putuword(PktHeader,PKTHEADER_ORIGNODE,pktfrom4d.Node);
putuword(PktHeader,PKTHEADER_DESTNODE,pktto4d.Node);
putuword(PktHeader,PKTHEADER_DAY,tp->tm_mday);
putuword(PktHeader,PKTHEADER_MONTH,tp->tm_mon);
putuword(PktHeader,PKTHEADER_YEAR,tp->tm_year+1900);
putuword(PktHeader,PKTHEADER_HOUR,tp->tm_hour);
putuword(PktHeader,PKTHEADER_MINUTE,tp->tm_min);
putuword(PktHeader,PKTHEADER_SECOND,tp->tm_sec);
putuword(PktHeader,PKTHEADER_BAUD,0);
putuword(PktHeader,PKTHEADER_PKTTYPE,2);
putuword(PktHeader,PKTHEADER_ORIGNET,pktfrom4d.Net);
putuword(PktHeader,PKTHEADER_DESTNET,pktto4d.Net);
PktHeader[PKTHEADER_PRODCODELOW]=0xfe;
PktHeader[PKTHEADER_REVMAJOR]=VERSION_MAJOR;
putuword(PktHeader,PKTHEADER_QORIGZONE,pktfrom4d.Zone);
putuword(PktHeader,PKTHEADER_QDESTZONE,pktto4d.Zone);
putuword(PktHeader,PKTHEADER_AUXNET,0);
putuword(PktHeader,PKTHEADER_CWVALIDCOPY,0x0100);
PktHeader[PKTHEADER_PRODCODEHIGH]=0;
PktHeader[PKTHEADER_REVMINOR]=VERSION_MINOR;
putuword(PktHeader,PKTHEADER_CAPABILWORD,0x0001);
putuword(PktHeader,PKTHEADER_ORIGZONE,pktfrom4d.Zone);
putuword(PktHeader,PKTHEADER_DESTZONE,pktto4d.Zone);
putuword(PktHeader,PKTHEADER_ORIGPOINT,pktfrom4d.Point);
putuword(PktHeader,PKTHEADER_DESTPOINT,pktto4d.Point);
PktHeader[PKTHEADER_PRODDATA]=0;
PktHeader[PKTHEADER_PRODDATA+1]=0;
PktHeader[PKTHEADER_PRODDATA+2]=0;
PktHeader[PKTHEADER_PRODDATA+3]=0;
for(c=0;c<8;c++)
PktHeader[PKTHEADER_PASSWORD+c]=0;
if(args[ARG_PASSWORD].data)
strncpy(&PktHeader[PKTHEADER_PASSWORD],args[ARG_PASSWORD].data,8);
/* Create message header */
attr=0;
if(!args[ARG_AREA].data)
attr|=FLAG_PVT;
if(args[ARG_FILEATTACH].data)
attr|=FLAG_FILEATTACH;
putuword(PktMsgHeader,PKTMSGHEADER_PKTTYPE,0x0002);
putuword(PktMsgHeader,PKTMSGHEADER_ORIGNODE,from4d.Node);
putuword(PktMsgHeader,PKTMSGHEADER_DESTNODE,to4d.Node);
putuword(PktMsgHeader,PKTMSGHEADER_ORIGNET,from4d.Net);
putuword(PktMsgHeader,PKTMSGHEADER_DESTNET,to4d.Net);
putuword(PktMsgHeader,PKTMSGHEADER_ATTR,attr);
putuword(PktMsgHeader,PKTMSGHEADER_COST,0);
mystrncpy(fromname,DEFAULT_FROMNAME,36);
mystrncpy(toname,DEFAULT_TONAME,36);
mystrncpy(subject,DEFAULT_SUBJECT,72);
mystrncpy(origin,DEFAULT_ORIGIN,80);
if(args[ARG_FROMNAME].data) mystrncpy(fromname,(char *)args[ARG_FROMNAME].data,36);
if(args[ARG_TONAME].data) mystrncpy(toname,(char *)args[ARG_TONAME].data,36);
if(args[ARG_SUBJECT].data) mystrncpy(subject,(char *)args[ARG_SUBJECT].data,72);
if(args[ARG_ORIGIN].data) mystrncpy(origin,(char *)args[ARG_ORIGIN].data,80);
MakeFidoDate(t,datetime);
/* Create pkt file */
serial=0;
do
{
t=time(NULL);
pktnum = (t<<8) + serial;
serial++;
sprintf(pktname,"%08x.pkt",pktnum);
MakeFullPath(args[ARG_DIR].data,pktname,fullname,200);
} while(osExists(fullname));
if(!(ofh=osOpen(fullname,MODE_NEWFILE)))
{
uint32_t err=osError();
printf("Unable to create packet %s\n",fullname);
printf("Error: %s\n",osErrorMsg(err));
osEnd();
exit(OS_EXIT_ERROR);
}
printf("Writing...\n");
printf(" From: %-36s (%u:%u/%u.%u)\n",fromname,from4d.Zone,from4d.Net,from4d.Node,from4d.Point);
printf(" To: %-36s (%u:%u/%u.%u)\n",toname,to4d.Zone,to4d.Net,to4d.Node,to4d.Point);
printf(" Subj: %s\n",subject);
printf(" Date: %s\n",datetime);
osWrite(ofh,PktHeader,SIZE_PKTHEADER);
osWrite(ofh,PktMsgHeader,SIZE_PKTMSGHEADER);
WriteNull(ofh,datetime);
WriteNull(ofh,toname);
WriteNull(ofh,fromname);
WriteNull(ofh,subject);
if(args[ARG_AREA].data)
{
osFPrintf(ofh,"AREA:%s\x0d",args[ARG_AREA].data);
}
else
{
if(from4d.Point)
osFPrintf(ofh,"\x01" "FMPT %d\x0d",from4d.Point);
if(to4d.Point)
osFPrintf(ofh,"\x01" "TOPT %d\x0d",to4d.Point);
osFPrintf(ofh,"\x01" "INTL %u:%u/%u %u:%u/%u\x0d",to4d.Zone,to4d.Net,to4d.Node,
from4d.Zone,from4d.Net,from4d.Node);
}
if(!args[ARG_NOMSGID].data)
{
osFPrintf(ofh,"\x01" "MSGID: %u:%u/%u.%u %08x\x0d",
from4d.Zone,from4d.Net,from4d.Node,from4d.Point,pktnum);
}
if(args[ARG_TEXT].data)
{
printf("Appending %s...\n",(char *)args[ARG_TEXT].data);
if(!(ifh=osOpen((char *)args[ARG_TEXT].data,MODE_OLDFILE)))
{
uint32_t err=osError();
printf("Unable to open \"%s\" for reading\n",(char *)args[ARG_TEXT].data);
printf("Error: %s\n",osErrorMsg(err));
osClose(ofh);
osDelete(fullname);
exit(OS_EXIT_ERROR);
}
while(osFGets(ifh,readbuf,100))
{
for(i=0;readbuf[i];i++)
if(readbuf[i] == '\n') readbuf[i]=0x0d;
osFPrintf(ofh,"%s",readbuf);
}
osClose(ifh);
}
if(args[ARG_AREA].data)
{
osFPrintf(ofh,"--- CrashWrite II/" OS_PLATFORM_NAME " " VERSION "\x0d");
osFPrintf(ofh," * Origin: %s (%u:%u/%u.%u)\x0d",origin,from4d.Zone,from4d.Net,from4d.Node,from4d.Point);
}
osWrite(ofh,"",1);
osWrite(ofh,"",1);
osWrite(ofh,"",1);
osClose(ofh);
osEnd();
exit(OS_EXIT_OK);
}