Add magimail (crashmail2 fork) to repo
This commit is contained in:
parent
8fad85affc
commit
807574ccf4
@ -5,7 +5,7 @@ JAMLIB = deps/jamlib/jamlib.a
|
||||
ZMODEM = deps/Xmodem/libzmodem.a
|
||||
LUA = deps/lua/liblua.a
|
||||
|
||||
all: magicka
|
||||
all: magicka magimail
|
||||
|
||||
${LUA}:
|
||||
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}
|
||||
$(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
|
||||
|
||||
clean:
|
||||
@ -30,3 +33,4 @@ clean:
|
||||
cd deps/lua && $(MAKE) clean
|
||||
cd deps/jamlib && $(MAKE) -f Makefile.linux clean
|
||||
cd deps/Xmodem && $(MAKE) clean
|
||||
cd utils/magimail && $(MAKE) cleanfreebsd
|
||||
|
@ -7,7 +7,7 @@ LUA = deps/lua/liblua.a
|
||||
B64 = deps/libb64-1.2/src/libb64.a
|
||||
MICROHTTPD=-lmicrohttpd
|
||||
|
||||
all: magicka
|
||||
all: magicka magimail
|
||||
|
||||
${LUA}:
|
||||
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}
|
||||
$(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
|
||||
|
||||
clean:
|
||||
@ -36,3 +39,4 @@ clean:
|
||||
cd deps/jamlib && $(MAKE) -f Makefile.linux clean
|
||||
cd deps/Xmodem && $(MAKE) clean
|
||||
cd deps/libb64-1.2 && $(MAKE) clean
|
||||
cd utils/magimail && $(MAKE) cleanfreebsd
|
||||
|
@ -6,7 +6,7 @@ ZMODEM = deps/Xmodem/libzmodem.a
|
||||
LUA = deps/lua/liblua.a
|
||||
|
||||
|
||||
all: magicka
|
||||
all: magicka magimail
|
||||
|
||||
${LUA}:
|
||||
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}
|
||||
$(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
|
||||
|
||||
clean:
|
||||
@ -31,3 +34,4 @@ clean:
|
||||
cd deps/lua && $(MAKE) clean
|
||||
cd deps/jamlib && $(MAKE) -f Makefile.linux clean
|
||||
cd deps/Xmodem && $(MAKE) clean
|
||||
cd utils/magimail && $(MAKE) cleanlinux
|
||||
|
@ -7,7 +7,7 @@ LUA = deps/lua/liblua.a
|
||||
B64 = deps/libb64-1.2/src/libb64.a
|
||||
MICROHTTPD=-lmicrohttpd
|
||||
|
||||
all: magicka
|
||||
all: magicka magimail
|
||||
|
||||
${LUA}:
|
||||
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}
|
||||
$(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
|
||||
|
||||
clean:
|
||||
@ -37,4 +40,4 @@ clean:
|
||||
cd deps/jamlib && $(MAKE) -f Makefile.linux clean
|
||||
cd deps/Xmodem && $(MAKE) clean
|
||||
cd deps/libb64-1.2 && $(MAKE) clean
|
||||
|
||||
cd utils/magimail && $(MAKE) cleanlinux
|
||||
|
@ -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
|
||||
|
||||
all: magicka
|
||||
all: magicka magimail
|
||||
|
||||
${LUA}:
|
||||
cd deps/lua && $(MAKE) -f Makefile macosx MAKEFLAGS=
|
||||
@ -24,6 +24,9 @@ ${ZMODEM}:
|
||||
magicka: $(OBJ) ${LUA} ${ZMODEM} ${JAMLIB}
|
||||
$(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
|
||||
|
||||
clean:
|
||||
@ -31,3 +34,4 @@ clean:
|
||||
cd deps/lua && $(MAKE) clean
|
||||
cd deps/jamlib && $(MAKE) -f Makefile.linux clean
|
||||
cd deps/Xmodem && $(MAKE) clean
|
||||
cd utils/magimail && $(MAKE) cleanlinux
|
||||
|
@ -8,7 +8,7 @@ B64 = deps/libb64-1.2/src/libb64.a
|
||||
MICROHTTPD=-lmicrohttpd
|
||||
|
||||
|
||||
all: magicka
|
||||
all: magicka magimail
|
||||
|
||||
${LUA}:
|
||||
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}
|
||||
$(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
|
||||
|
||||
clean:
|
||||
@ -36,3 +39,4 @@ clean:
|
||||
cd deps/lua && $(MAKE) clean
|
||||
cd deps/jamlib && $(MAKE) -f Makefile.linux clean
|
||||
cd deps/Xmodem && $(MAKE) clean
|
||||
cd utils/magimail && $(MAKE) cleanlinux
|
||||
|
25
utils/magimail/Makefile
Normal file
25
utils/magimail/Makefile
Normal 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
75
utils/magimail/README
Normal 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.
|
||||
|
114
utils/magimail/doc/AreafixHelp.txt
Normal file
114
utils/magimail/doc/AreafixHelp.txt
Normal 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.
|
505
utils/magimail/doc/ReadMe.txt
Normal file
505
utils/magimail/doc/ReadMe.txt
Normal 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
|
||||
|
||||
|
714
utils/magimail/doc/example.prefs
Normal file
714
utils/magimail/doc/example.prefs
Normal 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
|
||||
|
296
utils/magimail/doc/filter.txt
Normal file
296
utils/magimail/doc/filter.txt
Normal 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
|
||||
|
||||
|
29
utils/magimail/src/Makefile
Normal file
29
utils/magimail/src/Makefile
Normal 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
|
||||
|
219
utils/magimail/src/Makefile.linux
Normal file
219
utils/magimail/src/Makefile.linux
Normal 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
|
||||
|
17
utils/magimail/src/cmnllib/Makefile.linux
Normal file
17
utils/magimail/src/cmnllib/Makefile.linux
Normal 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
|
||||
|
149
utils/magimail/src/cmnllib/cmnllib.c
Normal file
149
utils/magimail/src/cmnllib/cmnllib.c
Normal 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];
|
||||
}
|
19
utils/magimail/src/cmnllib/cmnllib.h
Normal file
19
utils/magimail/src/cmnllib/cmnllib.h
Normal 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;
|
1703
utils/magimail/src/magimail/areafix.c
Normal file
1703
utils/magimail/src/magimail/areafix.c
Normal file
File diff suppressed because it is too large
Load Diff
14
utils/magimail/src/magimail/areafix.h
Normal file
14
utils/magimail/src/magimail/areafix.h
Normal 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);
|
||||
|
||||
|
2373
utils/magimail/src/magimail/config.c
Normal file
2373
utils/magimail/src/magimail/config.c
Normal file
File diff suppressed because it is too large
Load Diff
377
utils/magimail/src/magimail/config.h
Normal file
377
utils/magimail/src/magimail/config.h
Normal 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
|
||||
|
||||
|
314
utils/magimail/src/magimail/dupe.c
Normal file
314
utils/magimail/src/magimail/dupe.c
Normal 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);
|
||||
}
|
||||
|
||||
|
9
utils/magimail/src/magimail/dupe.h
Normal file
9
utils/magimail/src/magimail/dupe.h
Normal file
@ -0,0 +1,9 @@
|
||||
#include "shared/types.h"
|
||||
|
||||
bool OpenDupeDB(void);
|
||||
void CloseDupeDB(void);
|
||||
|
||||
bool CheckDupe(struct MemMessage *mm);
|
||||
|
||||
|
||||
|
978
utils/magimail/src/magimail/filter.c
Normal file
978
utils/magimail/src/magimail/filter.c
Normal 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);
|
||||
}
|
4
utils/magimail/src/magimail/filter.h
Normal file
4
utils/magimail/src/magimail/filter.h
Normal file
@ -0,0 +1,4 @@
|
||||
bool Filter(struct MemMessage *mm);
|
||||
bool CheckFilter(char *filter,char *cfgerr);
|
||||
|
||||
|
1732
utils/magimail/src/magimail/handle.c
Normal file
1732
utils/magimail/src/magimail/handle.c
Normal file
File diff suppressed because it is too large
Load Diff
7
utils/magimail/src/magimail/handle.h
Normal file
7
utils/magimail/src/magimail/handle.h
Normal 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);
|
||||
|
134
utils/magimail/src/magimail/logwrite.c
Normal file
134
utils/magimail/src/magimail/logwrite.c
Normal 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);
|
||||
}
|
||||
|
15
utils/magimail/src/magimail/logwrite.h
Normal file
15
utils/magimail/src/magimail/logwrite.h
Normal 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,...);
|
720
utils/magimail/src/magimail/magimail.c
Normal file
720
utils/magimail/src/magimail/magimail.c
Normal 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);
|
||||
}
|
89
utils/magimail/src/magimail/magimail.h
Normal file
89
utils/magimail/src/magimail/magimail.h
Normal 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[];
|
||||
|
||||
|
56
utils/magimail/src/magimail/mb.c
Normal file
56
utils/magimail/src/magimail/mb.c
Normal 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
|
||||
}
|
||||
};
|
20
utils/magimail/src/magimail/mb.h
Normal file
20
utils/magimail/src/magimail/mb.h
Normal 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
|
1339
utils/magimail/src/magimail/mb_jam.c
Normal file
1339
utils/magimail/src/magimail/mb_jam.c
Normal file
File diff suppressed because it is too large
Load Diff
5
utils/magimail/src/magimail/mb_jam.h
Normal file
5
utils/magimail/src/magimail/mb_jam.h
Normal 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));
|
593
utils/magimail/src/magimail/mb_msg.c
Normal file
593
utils/magimail/src/magimail/mb_msg.c
Normal 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);
|
||||
}
|
5
utils/magimail/src/magimail/mb_msg.h
Normal file
5
utils/magimail/src/magimail/mb_msg.h
Normal 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));
|
628
utils/magimail/src/magimail/mb_sq3.c
Normal file
628
utils/magimail/src/magimail/mb_sq3.c
Normal 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;
|
||||
}
|
5
utils/magimail/src/magimail/mb_sq3.h
Normal file
5
utils/magimail/src/magimail/mb_sq3.h
Normal 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));
|
539
utils/magimail/src/magimail/memmessage.c
Normal file
539
utils/magimail/src/magimail/memmessage.c
Normal 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);
|
||||
}
|
83
utils/magimail/src/magimail/memmessage.h
Normal file
83
utils/magimail/src/magimail/memmessage.h
Normal 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
|
||||
|
938
utils/magimail/src/magimail/misc.c
Normal file
938
utils/magimail/src/magimail/misc.c
Normal 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);
|
||||
}
|
53
utils/magimail/src/magimail/misc.h
Normal file
53
utils/magimail/src/magimail/misc.h
Normal 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);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
39
utils/magimail/src/magimail/nl.c
Normal file
39
utils/magimail/src/magimail/nl.c
Normal 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 }
|
||||
};
|
||||
|
17
utils/magimail/src/magimail/nl.h
Normal file
17
utils/magimail/src/magimail/nl.h
Normal 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
|
65
utils/magimail/src/magimail/nl_cmnl.c
Normal file
65
utils/magimail/src/magimail/nl_cmnl.c
Normal 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);
|
||||
}
|
5
utils/magimail/src/magimail/nl_cmnl.h
Normal file
5
utils/magimail/src/magimail/nl_cmnl.h
Normal 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);
|
437
utils/magimail/src/magimail/nl_v7p.c
Normal file
437
utils/magimail/src/magimail/nl_v7p.c
Normal 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,®ion))
|
||||
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,®ion))
|
||||
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);
|
||||
}
|
||||
*/
|
5
utils/magimail/src/magimail/nl_v7p.h
Normal file
5
utils/magimail/src/magimail/nl_v7p.h
Normal 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);
|
999
utils/magimail/src/magimail/outbound.c
Normal file
999
utils/magimail/src/magimail/outbound.c
Normal 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);
|
||||
}
|
||||
|
7
utils/magimail/src/magimail/outbound.h
Normal file
7
utils/magimail/src/magimail/outbound.h
Normal 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);
|
960
utils/magimail/src/magimail/pkt.c
Normal file
960
utils/magimail/src/magimail/pkt.c
Normal 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);
|
||||
}
|
||||
|
6
utils/magimail/src/magimail/pkt.h
Normal file
6
utils/magimail/src/magimail/pkt.h
Normal 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);
|
||||
|
||||
|
24
utils/magimail/src/magimail/safedel.c
Normal file
24
utils/magimail/src/magimail/safedel.c
Normal 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);
|
||||
}
|
2
utils/magimail/src/magimail/safedel.h
Normal file
2
utils/magimail/src/magimail/safedel.h
Normal file
@ -0,0 +1,2 @@
|
||||
bool SafeDelete(char *file);
|
||||
void ProcessSafeDelete(void);
|
306
utils/magimail/src/magimail/scan.c
Normal file
306
utils/magimail/src/magimail/scan.c
Normal 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);
|
||||
}
|
||||
|
4
utils/magimail/src/magimail/scan.h
Normal file
4
utils/magimail/src/magimail/scan.h
Normal file
@ -0,0 +1,4 @@
|
||||
bool Scan(void);
|
||||
bool ScanList(char *file);
|
||||
bool ScanDotJam(char *file);
|
||||
bool ScanArea(char *tagname);
|
191
utils/magimail/src/magimail/stats.c
Normal file
191
utils/magimail/src/magimail/stats.c
Normal 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);
|
||||
}
|
2
utils/magimail/src/magimail/stats.h
Normal file
2
utils/magimail/src/magimail/stats.h
Normal file
@ -0,0 +1,2 @@
|
||||
bool ReadStats(char *file);
|
||||
bool WriteStats(char *file);
|
326
utils/magimail/src/magimail/toss.c
Normal file
326
utils/magimail/src/magimail/toss.c
Normal 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);
|
||||
}
|
||||
|
3
utils/magimail/src/magimail/toss.h
Normal file
3
utils/magimail/src/magimail/toss.h
Normal file
@ -0,0 +1,3 @@
|
||||
bool TossFile(char *file);
|
||||
bool TossDir(char *dir);
|
||||
|
13
utils/magimail/src/magimail/version.h
Normal file
13
utils/magimail/src/magimail/version.h
Normal 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 */
|
||||
|
20
utils/magimail/src/oslib/os.h
Normal file
20
utils/magimail/src/oslib/os.h
Normal 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
|
||||
|
20
utils/magimail/src/oslib/osdir.h
Normal file
20
utils/magimail/src/oslib/osdir.h
Normal 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
|
30
utils/magimail/src/oslib/osfile.h
Normal file
30
utils/magimail/src/oslib/osfile.h
Normal 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
|
10
utils/magimail/src/oslib/osmem.h
Normal file
10
utils/magimail/src/oslib/osmem.h
Normal 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
|
21
utils/magimail/src/oslib/osmisc.h
Normal file
21
utils/magimail/src/oslib/osmisc.h
Normal 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
|
10
utils/magimail/src/oslib/ospattern.h
Normal file
10
utils/magimail/src/oslib/ospattern.h
Normal 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
|
34
utils/magimail/src/oslib_linux/Makefile
Normal file
34
utils/magimail/src/oslib_linux/Makefile
Normal 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
|
||||
|
13
utils/magimail/src/oslib_linux/os.c
Normal file
13
utils/magimail/src/oslib_linux/os.c
Normal file
@ -0,0 +1,13 @@
|
||||
#include <stdio.h>
|
||||
|
||||
#include <oslib/os.h>
|
||||
|
||||
bool osInit(void)
|
||||
{
|
||||
return(TRUE);
|
||||
}
|
||||
|
||||
void osEnd(void)
|
||||
{
|
||||
}
|
||||
|
33
utils/magimail/src/oslib_linux/os_linux.h
Normal file
33
utils/magimail/src/oslib_linux/os_linux.h
Normal 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
|
||||
|
100
utils/magimail/src/oslib_linux/osdir.c
Normal file
100
utils/magimail/src/oslib_linux/osdir.c
Normal 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);
|
||||
}
|
143
utils/magimail/src/oslib_linux/osfile.c
Normal file
143
utils/magimail/src/oslib_linux/osfile.c
Normal 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);
|
||||
}
|
19
utils/magimail/src/oslib_linux/osmem.c
Normal file
19
utils/magimail/src/oslib_linux/osmem.c
Normal 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);
|
||||
}
|
99
utils/magimail/src/oslib_linux/osmisc.c
Normal file
99
utils/magimail/src/oslib_linux/osmisc.c
Normal 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;
|
||||
}
|
40
utils/magimail/src/oslib_linux/ospattern.c
Normal file
40
utils/magimail/src/oslib_linux/ospattern.c
Normal 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);
|
||||
}
|
423
utils/magimail/src/shared/expr.c
Normal file
423
utils/magimail/src/shared/expr.c
Normal 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);
|
||||
}
|
||||
}
|
||||
|
11
utils/magimail/src/shared/expr.h
Normal file
11
utils/magimail/src/shared/expr.h
Normal 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);
|
||||
|
92
utils/magimail/src/shared/fidonet.h
Normal file
92
utils/magimail/src/shared/fidonet.h
Normal 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
|
96
utils/magimail/src/shared/jblist.c
Normal file
96
utils/magimail/src/shared/jblist.c
Normal 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);
|
||||
}
|
||||
}
|
21
utils/magimail/src/shared/jblist.h
Normal file
21
utils/magimail/src/shared/jblist.h
Normal 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
|
78
utils/magimail/src/shared/jbstrcpy.c
Normal file
78
utils/magimail/src/shared/jbstrcpy.c
Normal 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);
|
||||
}
|
||||
|
7
utils/magimail/src/shared/jbstrcpy.h
Normal file
7
utils/magimail/src/shared/jbstrcpy.h
Normal 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
|
12
utils/magimail/src/shared/mystrncpy.c
Normal file
12
utils/magimail/src/shared/mystrncpy.c
Normal 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;
|
||||
}
|
||||
|
8
utils/magimail/src/shared/mystrncpy.h
Normal file
8
utils/magimail/src/shared/mystrncpy.h
Normal 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
|
100
utils/magimail/src/shared/parseargs.c
Normal file
100
utils/magimail/src/shared/parseargs.c
Normal 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");
|
||||
}
|
||||
|
24
utils/magimail/src/shared/parseargs.h
Normal file
24
utils/magimail/src/shared/parseargs.h
Normal 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
|
57
utils/magimail/src/shared/path.c
Normal file
57
utils/magimail/src/shared/path.c
Normal 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);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
5
utils/magimail/src/shared/path.h
Normal file
5
utils/magimail/src/shared/path.h
Normal file
@ -0,0 +1,5 @@
|
||||
|
||||
void MakeFullPath(char *path,char *file,char *dest,uint32_t destsize);
|
||||
char *GetFilePart(char *str);
|
||||
|
||||
|
21
utils/magimail/src/shared/storedmsg.h
Normal file
21
utils/magimail/src/shared/storedmsg.h
Normal 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 */
|
||||
};
|
11
utils/magimail/src/shared/types.h
Normal file
11
utils/magimail/src/shared/types.h
Normal 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
|
358
utils/magimail/src/tools/magiexport.c
Normal file
358
utils/magimail/src/tools/magiexport.c
Normal 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);
|
||||
}
|
||||
|
156
utils/magimail/src/tools/magigetnode.c
Normal file
156
utils/magimail/src/tools/magigetnode.c
Normal 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);
|
||||
}
|
||||
|
341
utils/magimail/src/tools/magilist.c
Normal file
341
utils/magimail/src/tools/magilist.c
Normal 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 */
|
||||
|
726
utils/magimail/src/tools/magilistout.c
Normal file
726
utils/magimail/src/tools/magilistout.c
Normal 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);
|
||||
}
|
||||
|
||||
|
1042
utils/magimail/src/tools/magimaint.c
Normal file
1042
utils/magimail/src/tools/magimaint.c
Normal file
File diff suppressed because it is too large
Load Diff
707
utils/magimail/src/tools/magistats.c
Normal file
707
utils/magimail/src/tools/magistats.c
Normal 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);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
359
utils/magimail/src/tools/magiwrite.c
Normal file
359
utils/magimail/src/tools/magiwrite.c
Normal 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);
|
||||
}
|
Reference in New Issue
Block a user