crashmail-0.71/0040755000000000000000000000000010101767036012107 5ustar rootrootcrashmail-0.71/doc/0040755000000000000000000000000007763461113012663 5ustar rootrootcrashmail-0.71/doc/ReadMe.txt0100644000000000000000000004012307763306170014557 0ustar rootroot 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 ========= 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 1999 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 src/ReadMe.txt 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 Toss the specified file. TOSSDIR Toss all files in the specified directory. SCANAREA Scan the specified area. SCANLIST Scan all areas listed in the specified file. SCANDOTJAM 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 RESCANNODE RESCANMAX Rescans the specied area for the specied node. If RESCANMAX is specified, it sets the maximum number of messages to rescan. SETTINGS 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 [GROUP ] 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 [SORT ] [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 [] 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: [] 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 BTPOINT crashgetnode [] 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 ] [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 ... 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 FROMADDR TONAME TOADDR SUBJECT Use these keywords to set the header of the message. You only need to enter TONAME and TOADDR for netmails. PKTFROMADDR PKTTOADDR 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 You can use this keyword to set a password for the packet. The maximum length of the password is eight characters. 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 The origin line for the message. This keyword has no effect for netmail messages. DIR The directory where the packet should be placed. TEXT 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 [] [] 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 .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 crashmail-0.71/doc/AreafixHelp.txt0100644000000000000000000001020007300264671015577 0ustar rootroot 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: [] ... --- 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. [] 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=] 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=] 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 Changes your AreaFix password to the new password specified after the command. %COMPRESS 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. crashmail-0.71/doc/example.prefs0100644000000000000000000004537607763460361015377 0ustar rootroot; Example configuration file for CrashMail II ; ; This file demonstrates all keywords you can use in the configuration file. ; ; General configuration ; ===================== ; ; SYSOP ; ; 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 ; LOGLEVEL ; ; 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 ; 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 ; MAXBUNDLESIZE ; ; 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 ; ; If CrashMail can't figure out the zone of a message in another way, the ; zone configured here is used. DEFAULTZONE 2 ; NODELIST ; ; 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 ; ; The inbound directory is the directory where CrashMail looks for .pkt files ; and bundles to toss. INBOUND "c:\\fido\\inbound" ; OUTBOUND ; ; The outbound directory is where CrashMail writes the flow files that tells ; the mailer what files to send. OUTBOUND "c:\\fido\\outbound" ; TEMPDIR ; ; This is the directory where CrashMail unpacks incoming bundles. ; TEMPDIR "c:\\fido\\temp" ; CREATEPKTDIR ; ; This is the directory where CrashMail stores created .pkt files until they ; are stored in the packet directory. CREATEPKTDIR "c:\\fido\\temp" ; PACKETDIR ; ; This is the directory where CrashMail stores generated bundles. PACKETDIR "c:\\fido\\packets" ; STATSFILE ; ; 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 ; ; 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 ; ; 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 ... ; ; 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 ... ; ; 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 ; ; 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 ; ; 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 ; 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 [] ; PKTFROM ; AREAFIXINFO ; DEFAULTGROUP ; REMOTEAF [NEEDSPLUS] ; REMOTESYSOP ; ; 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 ; ; The file that is sent when a downlink issues a %HELP command. AREAFIXHELP "c:\\fido\\AreafixHelp.txt" ; AREAFIXMAXLINES ; ; The maximum number of lines in an AreaFix response. CrashMail splits the ; response if it exceeds this number. ; AREAFIXMAXLINES 50 ; AREAFIXNAME ; ; A name that CrashMail's AreaFix should respond to. AREAFIXNAME "AreaFix" AREAFIXNAME "AreaMgr" AREAFIXNAME "CrashMail" ; AREALIST [GROUP ] [FORWARD] [DESC] ; ; This is a list of the areas that are available at a node. It should contain ; lines with the format " ". 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 ; ; 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 .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 ; ; 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 ; ; ; ... ;FILTER SOURCE=TOSSED and TYPE=ECHOMAIL and TONAME="Johan Billing" ;COPY PERSONAL_MESSAGES ; Areas ; ===== ; ; AREA/NETMAIL/LOCALAREA [ ] ; IMPORT/EXPORT ... ; BANNED ... ; DESCRIPTION ; GROUP ; KEEPNUM ; KEEPDAYS ; 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 "[]" 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_ where 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 crashmail-0.71/doc/filter.txt0100644000000000000000000002027110073762251014703 0ustar rootroot 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 ... 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: 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 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 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 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 Writes the message to the BAD area with 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 BOUNCEHEADER 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 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 crashmail-0.71/doc/History.txt0100644000000000000000000003740510073765750015075 0ustar rootrootVersion 0.7 was probably the last major revision of CrashMail. If you are using CrashMail, please send me an e-mail (billing@df.lth.se). I am curious about how many CrashMail users there still are... Changes in version 0.71 - Fixed a bug that could cause CrashMail to crash when exporting messages from a JAM area with deleted messages. - Updated JAMLIB to 1.3.2 - Win32 binaries are now compiled with MinGW 3.1.0-1 instead of gcc-2.95-mingw32. Changes in version 0.7 - Implemented a message filter. Using this feature, you can filter out messages that match specified criteria and perform a number of commands on them. This filter will for example copy echomail messages addressed to me to a special area (the area needs to be configured as a local area using LOCALAREA): FILTER SOURCE=TOSSED and TYPE=ECHOMAIL and TONAME="Johan Billing" COPY PERSONAL_MESSAGES See doc/filter.txt for a complete description of the new message filter. - The new message filter replaces the configuration keywords ROBOTNAME, REMAP and REMAPNODE since the message filter can perform these tasks. Replacement for ROBOTNAME : FILTER TYPE=NETMAIL and TOLOCALAKA and TONAME= EXECUTE Replacement for REMAP FILTER TYPE=NETMAIL and TOLOCALAKA and TONAME= REMAPMSG Replacement for REMAPNODE FILTER TYPE=NETMAIL and TOADDR= REMAPMSG "*" - Rewrote the dupe-checking. CrashMail now no longer needs to load the entire dupe buffer into memory. This means that you now can keep a much large dupe buffer without using a lot of memory. CrashMail will not read your old dupe file, you have to delete it. Also note that the second argument for DUPEFILE has changed from the size of the dupe buffer in KB to the maximum number of messages that should be stored in the dupe buffer. If you don't update your configuration, you will only have a very small dupe buffer. - CrashMail no longer keeps zero-length files in the packet directory for use in naming new bundles. Instead it relies solely on the cmindex file. - CrashMail now also supports nodelists in the Version 7+ format in addition to its own format. (Note: It seems like the Linux version of FastLst does not include hub/region in the compiled nodelist for some reason. This means that node patterns with HUB/REGION won't work.) - New tool in the CrashMail suite: crashlistout. This tool can list your outbound directory in a pretty way. - New configuration keywords: BEFORETOSS and BEFOREPACK. You can use these to execute custom commands before tossing/packing a *.pkt file. - New keyword PKTFROM in node configuration. You can use this if you want to set the originating address of .pkt files to something other than the default. - New configuration switches: FLOWCRLF and NOEXPORTNETMAIL. FLOWCRLF makes CrashMail use CRLF as end-of-line characters in flow files instead of just LF. NOEXPORTNETMAIL makes CrashMail ignore netmail areas with SCAN and SCANLIST. This together with NOROUTE makes it possible to use an external program for handling netmail. - New switch NEEDSPLUS for the REMOTEAF keyword. - New commandline argument: SCANDOTJAM. This can be used for scanning areas listed in echomail.jam/netmail.jam files. - In addition to "programname ?", you can now also use -h, --help, help, /? and /h with CrashMail and the related utilities to show the commandline help. - Improved the time it takes for CrashMail to load the configuration file. Only noticable if you have a huge number of pass-through areas. - Fixed some bugs found in the ChangeLog from CrashEcho (thanks guys!) - SCANLIST does not abort anymore if an area cannot be scanned - RESCAN was broken and always returned an "unknown area" error - Added sanity checks to JAM linking to prevent CrashMail from crashing on messagebases with broken reply links - Fixed some memory leaks in the JAM handling. - Upgraded JAMLIB to version 1.3.1 - Some minor cosmetic changes. - Cleaned up the source in various places. Changes in version 0.62: CrashMail - CrashMail would check packet passwords even if the command-line option NOSECURITY was used. Fixed. - The Local flag is now cleared and the Sent flag is set before messages are imported to the messagebase. In previous versions of CrashMail, imported messages with Local flag and no Sent flag were re-exported the next time CrashMail SCAN was run. Fixed. - CrashMail no longer leaves empty lines in the config file when areas are removed by the AreaFix. CrashMaint - CrashMaint used local time instead of UTC when deleting old messages in JAM areas. This could cause messages to be deleted ahead of time. Thanks to Alexander S Aganichev for noticing this and sending me a patch. JAMLIB - There was a bug in JAMLIB that caused the Linux version of CrashMail to fail when trying to import an empty message to the messagebase. The bug has been fixed and CrashMail now uses the new version of JAMLIB. Changes in version 0.61: CrashMail: - CrashMail incorrectly bounced netmails to nodes listed as hold in the nodelist are no longer bounced. Fixed. Netmails to nodes listed as down are still bounced. - The CrashMail REMOVE command didn't work. Fixed. - The AreaFix would sometimes miss some areas when you unsubscribed to areas using patterns. - The AreaFix no longer crashes when it tries to remove areas after the feed has unsubscribed to them. - JAM_LINK and JAM_HIGHWATER would turn on both linking and the use of highwater marks. Fixed. - TINYSEENBY didn't work. Fixed. - CrashMail had problems with backslashes in file-attaches. Fixed. JAMLIB - Changed to latest version of JAMLIB. CrashWrite: - PKTFROMADDR/PKTTOADDR didn't work. Fixed. - CrashWrite had problems with paragraphs longer than 100 characters. Fixed. Changes in version 0.6 CrashMail: - The AreaFix no longer truncates area names longer than 30 characters in the response messages. - The Linux version of CrashMail now shows the real return code (using WEXITSTATUS()) when an external command returns an error. - Two default areas may now have the same path - Cleaned up the Makefiles - CrashMail no longer sets the Sent flag on all imported message. CrashMail now only exports messages with the Local flag set and the Sent flag cleared. - CrashMail can now also export JAM messages with very long kludges without problems. Previous versions had problems with kludges longer than 200 chars. - LF characters are stripped when importing messsages to a JAM messagebase. - Space characters are stripped in AreaFix commands. This means that AreaFix commands will work even if they begin with one or several space characters. - Node numbers can now be abbreviated on the EXPORT lines. See example.prefs for an example on how this works. Thanks to Per Lundberg for idea and original patch. - You can now define local areas in crashmail.prefs using the keyword LOCALAREA. Local areas are not used by CrashMail, but are included in config files created by CrashExport and are maintained when running CrashMaint. CrashWrite: - There are two new options PKTFROMADDR and PKTTOADDR that can be used to set the origin and destination address to something other than the origin and destination address of the message inside the packet. - A new option PASSWORD that can be used to set the password of the created packet. JAMLIB: - JAMLIB could crash on corrupt messagebases. Fixed. - JAMLIB lo longer reads or writes structures directly from/to disk. This makes JAMLIB even more portable and ensures that the Intel byte-order will be used on all platforms regardless of the processor used. All programs: - The Win32 version of CrashMail did not work if you were tossing mail to many downlinks since you could only open a limited number of files with fopen() (about 40). Because of this, the Win32 version has been rewritten to use Windows' I/O functions rather than the standard C stdio. The problem is solved and the Win32 version is now also slightly faster. Note that JAMLIB still uses fopen() so do not use too high a value for JAM_MAXOPEN. - Improved the error messages in all programs. Now CrashMail will also tell you why an I/O error occurred using the response given by the operating system. (To do this, the functions osError() and osErrorMsg() were added to oslib.) - Added function osVFPrintf() to oslib - Changed error message "Too many arguments" in command line parsing to to "Unknown keyword %s". This should make it easier to find the problem. - Several cosmetic changes to program output and source code Changes in version 0.52 CrashMail: - Three new flags for the NODE keyword: CRASH, DIRECT and HOLD. With these flags, you can set the priority for packed and unpacked netmail. - When the packet directory was missing, the error message said that the outbound directory was missing. This could be very confusing. Fixed. - Fixed a Y2K-related bug in the JAM import function. - Node patterns with REGION or HUB did not work for points. Fixed. - Added the new %-code %R for the ROBOTNAME keyword. %R gives the message in RFC-format with the addresses in RFC-format (name@pX.fX.nX.zX.domain). - When importing messages, CrashMail now checks for robot and AreaFix names before messages are remapped. If you want to remap messages to AreaFix, you have to make sure that no AreaFix names are configured. REMAPNODE still works as before. - CrashMail now updates the DateProcessed field when exporting messages from a JAM area. - CrashMail no longer is so strict with names of packet files names. Packet names are now considered valid even if they contain non-hexadecimal characters. - When glibc 2.1 was used, the Linux version of CrashMail exported messages from JAM messagebases with an incorrect date. The time was one hour ahead. This has now been fixed. - Dates in Via lines were one month early. Fixed. - If a netmail area had an IMPORT line, all netmails would be imported to that area. This has been fixed and IMPORT now works as intended. - CrashMail no longer aborts if a JAM area could not be opened when exporting messages. CrashMail instead continues and exports mail from all other areas. - CrashMail used to create an invalid configuration file when auto-adding areas to a config file where the last line did not end with an end-of-line character. This has now been fixed. - You can now use the environment variable CMCONFIGFILE to set the default configuration file for CrashMail. - CrashMail would incorrectly import FMPT kludges to JAM areas. Fixed. CrashExport: - CrashExport did not write netmail areas correctly to a GoldED configuration file. This has now been fixed. - CrashExport can now also create en area configuration file for timEd. - CrashExport no longer exports areas with the UNCONFIRMED keyword. CrashStats: - The total number of messages per day were not calculated correctly in the LAST7 mode, instead a random number would be shown. The average total number of messages per day was also incorrect. These bugs have now been fixed. CrashMaint: - You can now use the environment variable CMCONFIGFILE to set the default configuration file for CrashMail. All programs: - The argument parsing has been improved. The main change for the user is that "programname ?" now gives a more helpful output. - The functions remove(), rename() and system() has been moved to the oslib. This change should not be noticable for the user. - Peter Karlsson has prepared man-pages for CrashMail and all related tools. Thanks, Peter! These are handy under Linux, but can also be used on other platforms if you install a "man"-program. - Peter Karlsson has ported CrashMail II to OS/2. Thanks, Peter! Changes in version 0.5 CrashMail: - Because of a bug in the pattern matching, an empty string would match any pattern. Fixed. - Areas belonging to the same group were not listed together in the area lists generated by the Areafix. - CrashMail showed the same error message twice when the packer returned an error when unarchiving a bundle. Fixed. - If the highwater mark was lower than the lowest messagenumber in a JAM area, CrashMail would still try to export messages beginning from the highwater mark. Unfortunately this would cause a crash because of another bug that appeared when CrashMail tried to export an unreadable message. All this has now been fixed. - CrashMail no longer stops exporting when it encounters an unreadable message - CrashMail no longer adds its own node number to the path if it already exists as the last node in the path lines. - CrashMail could sometimes create circular reply links and get caught in infinite loops when dupes were imported to a JAM messagebase. Fixed. - New config option: ALLOWKILLSENT - New command-line keyword for CrashMail: TOSSDIR - New command-line keyword for CrashMail: NOSECURITY. If this keyword is used, all packets will be tossed without security checks. This is mainly intended to be used together with TOSSFILE/TOSSDIR and packets generated by CrashWrite. CrashMaint: - CrashMaint no longer checks the ActiveMsgs counter in the JAM messagebase to determine if the area needs to be packed. This check did not always work, among other things because all programs did not update the counter properly. JAM areas are now always packed when "crashmaint pack" is used. - CrashMaint now rebuilds the ActiveMsgs counter when packing a JAM area. - CrashMaint did not update the messagebase header when removing all messages from a JAM area. This would cause some messages not to be exported when highwater marks were used. (If you suspect that this has happened to you, remove all *.cmhw files.) - Improved the error handling a bit in CrashMaint. Now you get an error if an area couldn't be updated since it was in use by another program. CrashWrite: - Included CrashWrite, a new tool for CrashMail. CrashWrite reads a text file and then creates a packet file that can be tossed by CrashMail. CrashExport: - CrashAreasBBS and CrashForward have been replaced by the new program CrashExport. In addition to the old formats, CrashExport can also create arealists in GoldED format. The old version of CrashAreasBBS had some trouble with pass-through areas, this is gone in CrashExport. Changes in version 0.42 - Fixed bug that occurred when sending mail to nodes with long addresses (e.g. 9999:8888/7777.6666) - Fixed an error message in the outbound handling - Fixed a bug that occurred when auto-adding pass-through areas - Fixed a small memory leak - CrashMail got caught in an infinite loop when an unknown nodelist format was specified in the config. This is now fixed. - CrashMail no longer segfaults at startup when pass-through areas are used! - CrashMail now adds packets to bundles in the correct order - CrashMail would under some circumstances use the same bundle for more than one node. This has been fixed and a mechanism that checks that the same bundle is not used for more than one node has been added. - Routing did not work properly when BOUNCEPOINTS was turned on. Fixed. - Removed an unnecessary linebreak from the bounce messages. - New configuration keyword: NOMAXOUTBOUNDZONE. See example.prefs for more information. - CrashList did not handle Pvt nodes correctly. Fixed. - There was a small mistake in the example configuration file. The keyword is REMOTEAF, not REMOTEAREAFIX. Changes in version 0.4 - First public release crashmail-0.71/man/0040755000000000000000000000000007300264671012666 5ustar rootrootcrashmail-0.71/man/crashgetnode.10100644000000000000000000000133207300264671015412 0ustar rootroot.TH CRASHGETNODE 1 1999-08-01 "Johan Billing" "CrashMail" .SH NAME crashgetnode \- Lookup node in CrashMail nodelist .SH SYNOPSIS .B crashgetnode node [nodelistdir] .SH DESCRIPTION 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. .SH OPTIONS .TP .I node The node address to be looked up. .TP .I nodelistdir The directory where the nodelist resides. .SH "SEE ALSO" .BR crashmail (1), .BR crashlist (1) .\".SH FILES .\".SH BUGS .SH AUTHOR CrashMail is written by Johan Billing . .PP This manual page was written by Peter Karlsson . crashmail-0.71/man/crashwrite.10100644000000000000000000000435507300264671015127 0ustar rootroot.TH CRASHWRITE 1 1999-08-01 "Johan Billing" "CrashMail" .SH NAME crashwrite \- Creates PKT file from text file .SH SYNOPSIS .B crashwrite DIR directory [FROMNAME string] [FROMADDR node] [TONAME string] [TOADDR node] [SUBJECT string] [AREA area] [ORIGIN origin] [TEXT filename] [NOMSGID] [FILEATTACH] [PKTFROMADDR node] [PKTTOADDR node] PASSWORD [string] .SH DESCRIPTION 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. .PP 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. .SH OPTIONS .PD 0 .TP .I FROMNAME string .TP .I FROMADDR node .TP .I TONAME string .TP .I TOADDR node .TP .I SUBJECT string Use these keywords to set the header of the message. You only need to enter TONAME and TOADDR for netmails. .PD .TP .PD 0 .TP .I PKTFROMADDR node .TP .I PKTTOADDR node 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. .PD .TP .I PASSWORD string You can use this keyword to set a password for the packet. The maximum length of the password is eight characters. .TP .I 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. .TP .I ORIGIN origin The origin line for the message. This keyword has no effect for netmail messages. .TP .I DIR directory The directory where the packet should be placed. .TP .I TEXT filename The name of a text file that should be included as the message text. .TP .I NOMSGID Prevents CrashWrite from adding a MSGID line. .TP .I FILEATTACH Sets the file-attach flag for netmails. The filename should be put in the subject line. .\"SH EXAMPLES .SH "SEE ALSO" .BR crashmail (1) .\"SH FILES .\"SH BUGS .SH AUTHOR CrashMail is written by Johan Billing .PP This manual page was written by Peter Karlsson crashmail-0.71/man/crashmaint.10100644000000000000000000000254507300264671015104 0ustar rootroot.TH CRASHMAINT 1 1999-08-01 "Johan Billing" "CrashMail" .SH NAME crashmaint \- Do maintanence on CrashMail message bases .SH SYNOPSIS .B crashmaint [MAINT] [PACK] [VERBOSE] [SETTINGS filename] [PATTERN pattern] .SH DESCRIPTION Deletes old messages according to .B KEEPNUM and .B KEEPDAYS in .IR crashmail.prefs . The program can do two different operations on a messagebase, .I MAINT and .IR PACK . The meaning of these two modes are different for different messagebase formats. .TP .B *.msg .I MAINT deletes messages and .I PACK renumbers the area. .TP .B JAM .I MAINT sets the Deleted flag for the messages. .I PACK removes all messages with the Deleted flag from the messagebase. .PP Both .I MAINT and .I PACK can be specified at the same time. .SH OPTIONS .TP .I SETTINGS filename Specifies that another config file than the default should be used. You can use the environment variable CMCONFIGFILE to set the default configuration file. .TP .I PATTERN pattern Lets you perform the operations on only some of your areas. .TP .I VERBOSE Gives you a lot of information which you don't really need. .SH EXAMPLES crashmaint MAINT PACK PATTERN R20_AMIGA* .SH "SEE ALSO" .BR crashmail (1) .\"BR crashmail.prefs (5) .\"SH FILES .\"SH BUGS .SH AUTHOR CrashMail is written by Johan Billing .PP This manual page was written by Peter Karlsson crashmail-0.71/man/crashexport.10100644000000000000000000000236507300264671015315 0ustar rootroot.TH CRASHEXPORT 1 1999-08-01 "Johan Billing" "CrashMail" .SH NAME crashexport \- Export CrashMail configuration .SH SYNOPSIS .B crashexport crashmail.prefs outputfile format [GROUP groups] .SH DESCRIPTION This command reads a CrashMail configuration file and creates an arealist. .SH OPTIONS .TP .I GROUP group Only areas in the specified groups are included. .SH FORMATS CrashExport can create lists in these formats: .TP .I AREASBBS A standard areas.bbs file that can be read by many programs .TP .I 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. .TP .I FORWARDNODESC Same as FORWARD but without area descriptions. .TP .I GOLDED Creates an area configuration file in GoldED format. .TP .I TIMED Creates an area configuration file in timEd format. .SH EXAMPLES .TP .I crashexport crashmail/crashmail.prefs golded.areas GOLDED Exports the configuration file .I crashmail/crashmail.prefs to a GoldEd area configuration in .IR golded.areas . .SH "SEE ALSO" .BR crashmail (1) .\"SH FILES .\"SH BUGS .SH AUTHOR CrashMail is written by Johan Billing .PP This manual page was written by Peter Karlsson crashmail-0.71/man/crashstats.10100644000000000000000000000211407300264671015122 0ustar rootroot.TH CRASHSTATS 1 1999-08-01 "Johan Billing" "CrashMail" .SH NAME crashstats \- Display CrashMail statistics .SH SYNOPSIS .B crashstats statsfile [SORT mode] [LAST7] [NONODES] [NOAREAS] .SH DESCRIPTION This command displays the statistics file created by CrashMail. .SH OPTIONS .TP .I statsfile The statistics file to look up information from. .TP .I SORT mode This keywords specifies the sort mode (see below for list of sort modes). .TP .I LAST7 Displays detailed information about the flow of messages in areas for the last seven days. .TP .I NONODES Hide node statistics. .TP .I NOAREAS Hide area statistics. .SH "SORT MODES" .TP .B a Sort alphabetically. .TP .B t Sort by total number of messages. .TP .B m Sort by msgs/day. .TP .B d Sort by first time messages were imported. .TP .B l Sort by last time messages were imported. .TP .B u Sort by number of dupes. .\"SH EXAMPLES .SH "SEE ALSO" .BR crashmail (1) .SH FILES .I crashmail.stats .\"SH BUGS .SH AUTHOR CrashMail is written by Johan Billing .PP This manual page was written by Peter Karlsson crashmail-0.71/man/crashlist.10100644000000000000000000000247307300264671014747 0ustar rootroot.TH CRASHLIST 1 1999-08-01 "Johan Billing" "CrashMail" .SH NAME crashlist \- Compile a CrashMail nodelist .SH SYNOPSIS .B crashlist dir .SH DESCRIPTION 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: .PP [] .PP 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. .PP .\"SH OPTIONS .\"SH EXAMPLES .SH "SEE ALSO" .BR crashmail (1), .BR crashgetnode (1) .SH FILES Example cmnodelist.prefs: .nf ; Configuration for CrashList ; ; Format: [] NODELIST BTPOINT .\"SH BUGS .SH AUTHOR CrashMail is written by Johan Billing .PP This manual page was written by Peter Karlsson crashmail-0.71/man/crashmail.10100644000000000000000000000700007300264671014705 0ustar rootroot.TH CRASHMAIL 1 1999-08-01 "Johan Billing" "CrashMail" .SH NAME crashmail \- A Fidonet *.JAM and MSG tosser .SH SYNOPSIS .B crashmail [SETTINGS filename] [SCAN] [TOSS] [TOSSFILE filename] [TOSSDIR directory] [SCANAREA area] [SCANLIST filename] [RESCAN area RESCANNODE node [RESCANMAX max]] [VERSION] [LOCK] [UNLOCK] [NOSECURITY] .SH DESCRIPTION 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. .SH OPTIONS .TP .I SCAN Scan all areas for messages to export. .TP .I TOSS Toss all .pkt files and bundles in inbound directory. .TP .I TOSSFILE filename Toss the specified file. .TP .I TOSSDIR directory Toss all files in the specified directory. .TP .I SCANAREA area Scan the specified area. .TP .I SCANLIST filename Scan all areas listed in the specified file. .TP .I RESCAN area .PD 0 .TP .I RESCANNODE node .TP .I RESCANMAX max Rescans the specied area for the specied node. If RESCANMAX is specified, it sets the maximum number of messages to rescan. .PD .TP .I SETTINGS filename Use this configuration file instead of the default.You can use the environment variable CMCONFIGFILE to set the default configuration file. .TP .I VERSION Show version information about CrashMail. .TP .I 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. .TP .I 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. .TP .I NOSECURITY Process all packets without security checks. This is intended to be used mainly with TOSSDIR/TOSSFILE and with packets created by CrashWrite. .\"SH EXAMPLES .SH "SEE ALSO" .BR crashexport (1), .BR crashlist (1), .BR crashmaint (1), .BR crashwrite (1), .BR crashgetnode (1), .BR crashstats (1) .SH FILES .I crashmail.prefs .SH BUGS .SS Win32 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 .I 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. .SS 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. .PP 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. .PP 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. .PP If the precompiled binaries in the CrashMail archive don't work on your system, you will have to compile your own. See .I src/ReadMe.txt for more information about this. .SH AUTHOR CrashMail is written by Johan Billing .PP This manual page was written by Peter Karlsson crashmail-0.71/src/0040755000000000000000000000000007762140564012710 5ustar rootrootcrashmail-0.71/src/ReadMe.txt0100644000000000000000000000100007300264670014563 0ustar rootrootHow to compile: Just type make linux or make win32 or make os2 depending on the platform which you want to compile CrashMail for. You will now find the binaries in the 'bin' directory. If you want to remove all object files that were created during the compilation, type make cleanlinux or make cleanwin32 or make cleanos2 Note: CrashMail was developed using gcc. If you are using another compiler, you will probably have to make some adjustments to the makefiles and perhaps also to the source. crashmail-0.71/src/obj/0040755000000000000000000000000010073763620013453 5ustar rootrootcrashmail-0.71/src/cmnllib/0040755000000000000000000000000010073763620014321 5ustar rootrootcrashmail-0.71/src/cmnllib/cmnllib.c0100644000000000000000000000502707300264670016106 0ustar rootroot#include #include #include #include #include #include #include #include "cmnllib.h" struct idx { ushort zone,net,node,point,region,hub; ulong offset; }; ulong cmnlerr; uchar *cmnlerrstr[] = { "", "Failed to open nodelist index", "Unknown format of nodelist index", "Unexpected end of file", "Node not found", "Failed to open nodelist" }; ushort cmnlgetuword(uchar *buf,ulong offset) { return (ushort)(buf[offset]+256*buf[offset+1]); } long cmnlgetlong(uchar *buf,ulong offset) { return (long) buf[offset]+ buf[offset+1]*256+ buf[offset+2]*256*256+ buf[offset+3]*256*256*256; } osFile cmnlOpenNL(uchar *dir) { osFile fh; uchar 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,uchar *dir,struct cmnlIdx *cmnlidx,uchar *line,ulong len) { uchar buf[200]; uchar nlname[100]; struct idx idx; bool found; osFile fh; uchar 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); } uchar *cmnlLastError(void) { return cmnlerrstr[cmnlerr]; } crashmail-0.71/src/cmnllib/cmnllib.h0100644000000000000000000000077507300264670016120 0ustar rootroot#include "shared/types.h" struct cmnlIdx { ushort 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(uchar *dir); void cmnlCloseNL(osFile nl); bool cmnlFindNL(osFile nl,uchar *dir,struct cmnlIdx *idx,uchar *line,ulong len); uchar *cmnlLastError(void); extern ulong cmnlerr; crashmail-0.71/src/cmnllib/Makefile.os20100644000000000000000000000034307300264670016460 0ustar rootrootINCDIR = ../ CC = gcc -DPLATFORM_OS2 -I $(INCDIR) -Wall AR = ar -ru RM = del 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 crashmail-0.71/src/cmnllib/Makefile.linux0100644000000000000000000000035007300264670017112 0ustar rootrootINCDIR = ../ CC = gcc -DPLATFORM_LINUX -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 crashmail-0.71/src/cmnllib/Makefile.win320100644000000000000000000000034607300264670016722 0ustar rootrootINCDIR = ../ CC = gcc -DPLATFORM_WIN32 -I $(INCDIR) -Wall AR = ar -ru RM = del 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 crashmail-0.71/src/Makefile0100644000000000000000000000237207300264670014342 0ustar rootroot# 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 win32 ............ Make Win32 binaries @echo make os2 .............. Make OS/2 binaries @echo make cleanlinux ....... Remove object files under Linux @echo make cleanwin32 ....... Remove object files under Win32 @echo make cleanos2 ......... Remove object files under OS/2 linux : make -C cmnllib -f Makefile.linux make -C jamlib -f Makefile.linux make -C oslib_linux make -f Makefile.linux win32 : make -C cmnllib -f Makefile.win32 make -C jamlib -f Makefile.win32 make -C oslib_win32 make -f Makefile.win32 os2 : make -C cmnllib -f Makefile.os2 make -C jamlib -f Makefile.os2 make -C oslib_os2 make -f Makefile.os2 cleanlinux : make -C cmnllib -f Makefile.linux clean make -C jamlib -f Makefile.linux clean make -C oslib_linux clean make -f Makefile.linux clean cleanwin32 : make -C cmnllib -f Makefile.win32 clean make -C jamlib -f Makefile.win32 clean make -C oslib_win32 clean make -f Makefile.win32 clean cleanos2 : make -C cmnllib -f Makefile.os2 clean make -C jamlib -f Makefile.os2 clean make -C oslib_os2 clean make -f Makefile.os2 clean crashmail-0.71/src/oslib_linux/0040755000000000000000000000000010073763620015230 5ustar rootrootcrashmail-0.71/src/oslib_linux/os.c0100644000000000000000000000015107300264671016010 0ustar rootroot#include #include bool osInit(void) { return(TRUE); } void osEnd(void) { } crashmail-0.71/src/oslib_linux/Makefile0100644000000000000000000000100507300264671016662 0ustar rootrootINCDIR = ../ CC = gcc -Wall -I $(INCDIR) -DPLATFORM_LINUX 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 crashmail-0.71/src/oslib_linux/osfile.c0100644000000000000000000000361607300264671016661 0ustar rootroot#include #include #include #include #include #include osFile osOpen(uchar *name,ulong 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); } ulong osRead(osFile os,void *buf,ulong bytes) { return fread(buf,1,bytes,(FILE *)os); } bool osPutChar(osFile os, uchar ch) { if(fputc(ch,(FILE *)os)==EOF) return(FALSE); return(TRUE); } bool osWrite(osFile os,const void *buf,ulong bytes) { if(fwrite(buf,1,bytes,(FILE *)os)!=bytes) return(FALSE); return(TRUE); } bool osPuts(osFile os,uchar *str) { if(fputs(str,(FILE *)os)==EOF) return(FALSE); return(TRUE); } ulong osFGets(osFile os,uchar *str,ulong 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 (ulong)strlen(s); } return(0); } ulong osFTell(osFile os) { return ftell((FILE *)os); } bool osFPrintf(osFile os,uchar *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,uchar *fmt,va_list args) { int res; res=vfprintf(os,fmt,args); if(!res) return(FALSE); return(TRUE); } void osSeek(osFile fh,ulong offset,short mode) { int md; if(mode == OFFSET_BEGINNING) md=SEEK_SET; if(mode == OFFSET_END) md=SEEK_END; fseek((FILE *)fh,offset,md); } crashmail-0.71/src/oslib_linux/osmisc.c0100644000000000000000000000243207762136240016672 0ustar rootroot#include #include #include #include #include #include #include #include #include #include #include void osSetComment(uchar *file,uchar *comment) { /* Does not exist in this os */ } /* Returns -1 if dir was not found and errorlevel otherwise */ int osChDirExecute(uchar *dir,uchar *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(uchar *cmd) { int res; res=system(cmd); return WEXITSTATUS(res); } bool osExists(uchar *file) { struct stat st; if(stat(file,&st) == 0) return(TRUE); return(FALSE); } bool osMkDir(uchar *dir) { if(mkdir(dir,0777) != 0) return(FALSE); return(TRUE); } bool osRename(uchar *oldfile,uchar *newfile) { if(rename(oldfile,newfile) == 0) return(TRUE); return(FALSE); } bool osDelete(uchar *file) { if(remove(file) == 0) return(TRUE); return(FALSE); } void osSleep(int secs) { sleep(secs); } uchar *osErrorMsg(ulong errnum) { return (uchar *)strerror(errnum); } ulong osError(void) { return (ulong)errno; } crashmail-0.71/src/oslib_linux/ospattern.c0100644000000000000000000000113607300264671017412 0ustar rootroot#include #include #include #include bool osCheckPattern(uchar *pattern) { return(TRUE); } bool osMatchPattern(uchar *pattern,uchar *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(uchar *pat) { if(strchr(pat,'?') || strchr(pat,'*')) return(TRUE); return(FALSE); } crashmail-0.71/src/oslib_linux/os_linux.h0100644000000000000000000000126607300264671017244 0ustar rootroot#include typedef unsigned short 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 crashmail-0.71/src/oslib_linux/osdir.c0100644000000000000000000000357607300264671016525 0ustar rootroot#include #include #include #include #include #include #include #include #include #include #include #include #include bool osReadDir(uchar *dirname,struct jbList *filelist,bool (*acceptfunc)(uchar *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(uchar *dirname,void (*func)(uchar *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(uchar *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); } crashmail-0.71/src/oslib_linux/osmem.c0100644000000000000000000000033707300264671016515 0ustar rootroot#include #include void *osAlloc(ulong size) { return malloc((size_t)size); } void *osAllocCleared(ulong size) { return calloc((size_t)size,1); } void osFree(void *buf) { free(buf); } crashmail-0.71/src/oslib_win32/0040755000000000000000000000000007300265276015036 5ustar rootrootcrashmail-0.71/src/oslib_win32/os.c0100644000000000000000000000016607300264670015620 0ustar rootroot#include #include bool osInit(void) { return(TRUE); } void osEnd(void) { } crashmail-0.71/src/oslib_win32/Makefile0100644000000000000000000000104307300264670016466 0ustar rootrootINCDIR = ../ CC = gcc -I $(INCDIR) -DPLATFORM_WIN32 -Wall AR = ar -ru RM = del 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 crashmail-0.71/src/oslib_win32/osfile.c0100644000000000000000000001600207300264670016454 0ustar rootroot#include #include /* Only for vsprintf() */ #include #include #include #define MIN(a,b) ((a)<(b)? (a):(b)) #define OSFILE_BUFSIZE 5000 #define LASTACCESS_READ 1 #define LASTACCESS_WRITE 2 struct osfile { HANDLE h; uchar *buf; int lastaccessmode; ulong bufmax; ulong buflen; ulong bufpos; ulong filepos; }; bool win32writebuffer(struct osfile *osf) { DWORD numberofbyteswritten; if(osf->bufpos == 0) return(TRUE); /* Nothing to do */ if(!WriteFile(osf->h,osf->buf,osf->bufpos,&numberofbyteswritten,NULL)) return(FALSE); if(numberofbyteswritten != osf->bufpos) return(FALSE); osf->bufpos=0; osf->buflen=0; return(TRUE); } bool win32readbuffer(struct osfile *osf) { DWORD numberofbytesread; if(!ReadFile(osf->h,osf->buf,osf->bufmax,&numberofbytesread,NULL)) return(FALSE); if(numberofbytesread == 0) return(FALSE); osf->buflen=numberofbytesread; osf->bufpos=0; return(TRUE); } bool win32setmoderead(struct osfile *osf) { if(osf->lastaccessmode == LASTACCESS_WRITE) { /* Flush write buffer */ if(!win32writebuffer(osf)) return(FALSE); osf->buflen=0; osf->bufpos=0; } osf->lastaccessmode = LASTACCESS_READ; return(TRUE); } bool win32setmodewrite(struct osfile *osf) { if(osf->lastaccessmode == LASTACCESS_READ) { /* File pointer needs to be adjusted */ SetFilePointer(osf->h,osf->filepos,NULL,FILE_END); osf->buflen=0; osf->bufpos=0; } osf->lastaccessmode = LASTACCESS_WRITE; return(TRUE); } osFile osOpen(uchar *name,ulong mode) { DWORD desiredaccess; DWORD sharemode; DWORD creationdisposition; struct osfile *os; if(!(os=osAllocCleared(sizeof(struct osfile)))) return(NULL); if(!(os->buf=osAlloc(OSFILE_BUFSIZE))) { osFree(os); return(NULL); } if(mode == MODE_NEWFILE) { desiredaccess=GENERIC_WRITE; sharemode=0; creationdisposition=CREATE_ALWAYS; } else if(mode == MODE_OLDFILE) { desiredaccess=GENERIC_READ; sharemode=FILE_SHARE_READ; creationdisposition=OPEN_EXISTING; } else { desiredaccess=GENERIC_READ | GENERIC_WRITE; sharemode=FILE_SHARE_READ | FILE_SHARE_WRITE; creationdisposition=OPEN_ALWAYS; } os->h=CreateFile(name,desiredaccess,sharemode,NULL, creationdisposition,FILE_ATTRIBUTE_NORMAL,NULL); if(os->h == INVALID_HANDLE_VALUE) { osFree(os->buf); osFree(os); return(NULL); } os->bufmax=OSFILE_BUFSIZE; return (osFile)os; } void osClose(osFile os) { struct osfile *osf=(struct osfile *)os; if(osf->lastaccessmode == LASTACCESS_WRITE) win32writebuffer(osf); CloseHandle(osf->h); osFree(osf->buf); osFree(osf); } ulong osRead(osFile os,void *buf,ulong bytes) { struct osfile *osf=(struct osfile *)os; ulong read,n; win32setmoderead(osf); read=0; if(osf->buflen-osf->bufpos != 0) { /* Copy what's left in the buffer */ n=MIN(osf->buflen-osf->bufpos,bytes); memcpy(buf,&osf->buf[osf->bufpos],n); osf->bufpos+=n; osf->filepos+=n; buf+=n; bytes-=n; read+=n; } if(bytes > osf->bufmax) { /* Larger than buffer, read directly */ DWORD numberofbytesread; if(!ReadFile(osf->h,buf,bytes,&numberofbytesread,NULL)) return(read); read+=numberofbytesread; osf->filepos+=numberofbytesread; } else if(bytes > 0) { /* Get rest from buffer */ if(!win32readbuffer(osf)) return(read); n=MIN(osf->buflen-osf->bufpos,bytes); memcpy(buf,&osf->buf[osf->bufpos],n); osf->bufpos+=n; osf->filepos+=n; buf+=n; bytes-=n; read+=n; } return(read); } int osGetChar(osFile os) { struct osfile *osf=(struct osfile *)os; win32setmoderead(osf); if(osf->buflen-osf->bufpos == 0) { /* Buffer needs to be refilled */ if(!win32readbuffer(osf)) return(-1); } osf->filepos++; return(osf->buf[osf->bufpos++]); } ulong osFGets(osFile os,uchar *str,ulong max) { ulong d; int ch; d=0; if(max==0) return(0); for(;;) { ch=osGetChar(os); if(ch == -1) /* End of file */ { str[d]=0; return(d); } if(ch == 10) /* End of line */ { str[d++]=ch; str[d]=0; return(d); } if(ch != 13) /* CRs are skipped */ str[d++]=ch; if(d == max-1) /* Buffer full */ { str[d]=0; return(d); } } } bool osWrite(osFile os,const void *buf,ulong bytes) { struct osfile *osf=(struct osfile *)os; DWORD numberofbyteswritten; win32setmodewrite(osf); if(bytes > osf->bufmax-osf->bufpos) { /* Will not fit in buffer */ if(!win32writebuffer(osf)) return(FALSE); } if(bytes > osf->bufmax) { /* Larger than buffer, write directly */ if(!WriteFile(osf->h,buf,bytes,&numberofbyteswritten,NULL)) return(FALSE); if(numberofbyteswritten != bytes) return(FALSE); osf->filepos+=bytes; } else { /* Put in buffer */ memcpy(&osf->buf[osf->bufpos],buf,bytes); osf->bufpos+=bytes; osf->filepos+=bytes; } return(TRUE); } bool osPutChar(osFile os, uchar ch) { struct osfile *osf=(struct osfile *)os; win32setmodewrite(osf); if(osf->bufpos == osf->bufmax) { if(!win32writebuffer(osf)) return(FALSE); } osf->buf[osf->bufpos++]=ch; osf->filepos++; return(TRUE); } bool osPuts(osFile os,uchar *str) { if(osWrite(os,str,strlen(str))!=strlen(str)) return(FALSE); return(TRUE); } bool osFPrintf(osFile os,uchar *fmt,...) { va_list args; uchar buf[1000]; va_start(args, fmt); vsprintf(buf,fmt,args); va_end(args); return osPuts(os,buf); } bool osVFPrintf(osFile os,uchar *fmt,va_list args) { uchar buf[1000]; vsprintf(buf,fmt,args); return osPuts(os,buf); } void osSeek(osFile os,ulong offset,short mode) { struct osfile *osf=(struct osfile *)os; DWORD movemethod; /* Flush buffer if needed */ if(osf->lastaccessmode == LASTACCESS_WRITE) win32writebuffer(osf); /* Empty buffer */ osf->buflen=0; osf->bufpos=0; osf->lastaccessmode=0; if(mode == OFFSET_BEGINNING) movemethod=FILE_BEGIN; if(mode == OFFSET_END) movemethod=FILE_END; osf->filepos=SetFilePointer(osf->h,offset,NULL,movemethod); } ulong osFTell(osFile os) { struct osfile *osf=(struct osfile *)os; return(osf->filepos); } crashmail-0.71/src/oslib_win32/os_win32.h0100644000000000000000000000132107300264670016641 0ustar rootroot#include #include bool osInit(void); void osEnd(void); typedef unsigned short UINT16; /* Unsigned 16-bit integer */ #define OS_EXIT_ERROR 10 #define OS_EXIT_OK 0 #define OS_PLATFORM_NAME "Win32" #define OS_CURRENT_DIR "." #define OS_PATH_CHARS "\\" #define OS_CONFIG_NAME "crashmail.prefs" #define OS_CONFIG_VAR "CMCONFIGFILE" /* 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 crashmail-0.71/src/oslib_win32/osmisc.c0100644000000000000000000000322007300264670016466 0ustar rootroot#include #include /* For system() */ #include #include #include #include void osSetComment(uchar *file,uchar *comment) { /* Does not exist in this os */ } /* Returns -1 if dir was not found and errorlevel otherwise */ int osChDirExecute(uchar *dir,uchar *cmd) { char olddir[300]; int res; if(!GetCurrentDirectory(300,olddir)) return(-1); if(!SetCurrentDirectory(dir)) return(-1); res=osExecute(cmd); SetCurrentDirectory(olddir); return(res); } int osExecute(uchar *cmd) { return system(cmd); } bool osExists(uchar *file) { HANDLE hFind; WIN32_FIND_DATA FindFileData; hFind = FindFirstFile(file,&FindFileData); FindClose(hFind); if (hFind == INVALID_HANDLE_VALUE) return(FALSE); return(TRUE); } bool osMkDir(uchar *dir) { if(CreateDirectory(dir,NULL)) return(TRUE); return(FALSE); } bool osRename(uchar *oldfile,uchar *newfile) { if(MoveFile(oldfile,newfile)) return(TRUE); return(FALSE); } bool osDelete(uchar *file) { if(DeleteFile(file)) return(TRUE); return(FALSE); } void osSleep(int secs) { Sleep(secs*1000); } uchar *osErrorMsg(ulong errnum) { uchar charbuf[1000]; static uchar oembuf[1000]; FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_MAX_WIDTH_MASK, NULL,(DWORD)errnum,0,charbuf,1000,NULL); CharToOem(charbuf,oembuf); return (uchar *)oembuf; } ulong osError(void) { return (ulong)GetLastError(); } crashmail-0.71/src/oslib_win32/ospattern.c0100644000000000000000000000114107300264670017210 0ustar rootroot#include #include #include #include bool osCheckPattern(uchar *pattern) { return(TRUE); } bool osMatchPattern(uchar *pattern,uchar *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(uchar *pat) { if(strchr(pat,'?') || strchr(pat,'*')) return(TRUE); return(FALSE); } crashmail-0.71/src/oslib_win32/osdir.c0100644000000000000000000000622107300264670016315 0ustar rootroot#include #include #include #include #include #include #include void win32finddata_to_fileentry(WIN32_FIND_DATA *w32,struct osFileEntry *fe) { FILETIME local; SYSTEMTIME systime; struct tm tp; mystrncpy(fe->Name,w32->cFileName,100); fe->Size=w32->nFileSizeLow; FileTimeToLocalFileTime(&w32->ftLastWriteTime,&local); FileTimeToSystemTime(&local,&systime); tp.tm_sec=systime.wSecond; tp.tm_min=systime.wMinute; tp.tm_hour=systime.wHour; tp.tm_mday=systime.wDay; tp.tm_mon=systime.wMonth-1; tp.tm_year=systime.wYear-1900; tp.tm_wday=0; tp.tm_yday=0; tp.tm_isdst=-1; fe->Date=mktime(&tp); if(fe->Date == -1) /* Just in case */ time(&fe->Date); } bool win32readdiraddfile(WIN32_FIND_DATA *FindFileData,struct jbList *filelist,bool (*acceptfunc)(uchar *filename)) { bool add; struct osFileEntry *tmp; if(!acceptfunc) add=TRUE; else add=(*acceptfunc)(FindFileData->cFileName); if(add) { if(!(tmp=(struct osFileEntry *)osAllocCleared(sizeof(struct osFileEntry)))) { jbFreeList(filelist); return(FALSE); } win32finddata_to_fileentry(FindFileData,tmp); jbAddNode(filelist,(struct jbNode *)tmp); } return(TRUE); } bool osReadDir(uchar *dirname,struct jbList *filelist,bool (*acceptfunc)(uchar *filename)) { WIN32_FIND_DATA FindFileData; HANDLE hFind; char buf[200]; jbNewList(filelist); mystrncpy(buf,dirname,190); if(buf[strlen(buf)-1] != '\\') strcat(buf,"\\"); strcat(buf,"*"); hFind = FindFirstFile(buf,&FindFileData); if (hFind == INVALID_HANDLE_VALUE) return(FALSE); if(!win32readdiraddfile(&FindFileData,filelist,acceptfunc)) { FindClose(hFind); return(FALSE); } while(FindNextFile(hFind,&FindFileData)) { if(!win32readdiraddfile(&FindFileData,filelist,acceptfunc)) { FindClose(hFind); return(FALSE); } } FindClose(hFind); return(TRUE); } bool osScanDir(uchar *dirname,void (*func)(uchar *file)) { WIN32_FIND_DATA FindFileData; HANDLE hFind; char buf[200]; mystrncpy(buf,dirname,190); if(buf[strlen(buf)-1] != '\\') strcat(buf,"\\"); strcat(buf,"*"); hFind = FindFirstFile(buf,&FindFileData); if (hFind == INVALID_HANDLE_VALUE) return(FALSE); (*func)(FindFileData.cFileName); while(FindNextFile(hFind,&FindFileData)) (*func)(FindFileData.cFileName); FindClose(hFind); return(TRUE); } struct osFileEntry *osGetFileEntry(uchar *file) { WIN32_FIND_DATA FindFileData; HANDLE hFind; struct osFileEntry *tmp; hFind = FindFirstFile(file,&FindFileData); FindClose(hFind); if (hFind == INVALID_HANDLE_VALUE) return(NULL); if(!(tmp=(struct osFileEntry *)osAllocCleared(sizeof(struct osFileEntry)))) return(NULL); win32finddata_to_fileentry(&FindFileData,tmp); return(tmp); } crashmail-0.71/src/oslib_win32/osmem.c0100644000000000000000000000036107300264670016314 0ustar rootroot#include #include void *osAlloc(ulong size) { return malloc((size_t)size); } void *osAllocCleared(ulong size) { return calloc((size_t)size,1); } void osFree(void *buf) { free(buf); } crashmail-0.71/src/oslib/0040755000000000000000000000000007300264671014012 5ustar rootrootcrashmail-0.71/src/oslib/os.h0100644000000000000000000000052007300264671014576 0ustar rootroot#ifndef OS_OS_H #define OS_OS_H #include bool osInit(void); void osEnd(void); #if defined(PLATFORM_WIN32) #include #elif defined(PLATFORM_LINUX) #include #elif defined(PLATFORM_OS2) #include #else #error Unsupported platform #endif #endif crashmail-0.71/src/oslib/osfile.h0100644000000000000000000000152507300264671015444 0ustar rootroot#ifndef OS_OSFILE_H #define OS_OSFILE_H #include #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(uchar *name,ulong mode); void osClose(osFile os); int osGetChar(osFile os); ulong osRead(osFile os,void *buf,ulong bytes); ulong osFGets(osFile os,uchar *str,ulong max); ulong osFTell(osFile os); bool osPutChar(osFile os, uchar ch); bool osWrite(osFile os,const void *buf, ulong bytes); bool osPuts(osFile os,uchar *str); bool osFPrintf(osFile os,uchar *fmt,...); bool osVFPrintf(osFile os,uchar *fmt,va_list args); void osSeek(osFile os,ulong offset,short mode); #endif crashmail-0.71/src/oslib/osmisc.h0100644000000000000000000000062307300264671015456 0ustar rootroot#ifndef OS_OSMISC_H #define OS_OSMISC_H #include "shared/types.h" void osSetComment(uchar *file,uchar *comment); bool osExists(uchar *file); int osChDirExecute(uchar *dir,uchar *cmd); int osExecute(uchar *cmd); bool osRename(uchar *oldfile,uchar *newfile); bool osDelete(uchar *file); bool osMkDir(uchar *dir); void osSleep(int secs); ulong osError(void); uchar *osErrorMsg(ulong errnum); #endif crashmail-0.71/src/oslib/ospattern.h0100644000000000000000000000031107300264671016172 0ustar rootroot#ifndef OS_OSPATTERN_H #define OS_OSPATTERN_H #include "shared/types.h" bool osCheckPattern(uchar *pattern); bool osMatchPattern(uchar *pattern,uchar *str); bool osIsPattern(uchar *pattern); #endif crashmail-0.71/src/oslib/osdir.h0100644000000000000000000000060507300264671015301 0ustar rootroot#ifndef OS_OSDIR_H #define OS_OSDIR_H #include "shared/types.h" #include struct osFileEntry { struct osFileEntry *Next; uchar Name[100]; time_t Date; ulong Size; }; bool osReadDir(uchar *dir,struct jbList *filelist,bool (*acceptfunc)(uchar *filename)); bool osScanDir(uchar *dir,void (*func)(uchar *file)); struct osFileEntry *osGetFileEntry(uchar *file); #endif crashmail-0.71/src/oslib/osmem.h0100644000000000000000000000023707300265375015304 0ustar rootroot#ifndef OS_OSMEM_H #define OS_OSMEM_H #include "shared/types.h" void *osAlloc(ulong size); void *osAllocCleared(ulong size); void osFree(void *buf); #endif crashmail-0.71/src/tools/0040755000000000000000000000000007762131601014040 5ustar rootrootcrashmail-0.71/src/tools/crashgetnode.c0100644000000000000000000000550007762222166016656 0ustar rootroot#include #include #include #include #include #include #include #include #define VERSION "1.0" #ifdef PLATFORM_AMIGA uchar *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(uchar *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; uchar 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=(uchar *)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((uchar *)args[ARG_NODE].data,&n4d)) { printf("Invalid node %s\n",(uchar *)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); } crashmail-0.71/src/tools/crashwrite.c0100644000000000000000000002323207762222102016353 0ustar rootroot#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define VERSION "1.1" #define VERSION_MAJOR 1 #define VERSION_MINOR 1 #ifdef PLATFORM_AMIGA uchar *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 CrashMail II" #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 } }; uchar PktMsgHeader[SIZE_PKTMSGHEADER]; uchar PktHeader[SIZE_PKTHEADER]; bool nomem,diskfull; ushort getuword(uchar *buf,ulong offset) { return (ushort)(buf[offset]+256*buf[offset+1]); } void putuword(uchar *buf,ulong offset,ushort num) { buf[offset]=num%256; buf[offset+1]=num/256; } void MakeFidoDate(time_t tim,uchar *dest) { struct tm *tp; time_t t; uchar *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,uchar *str) { osWrite(ofh,str,(ulong)(strlen(str)+1)); } int main(int argc, char **argv) { struct Node4D from4d,to4d,pktfrom4d,pktto4d; osFile ifh,ofh; time_t t; struct tm *tp; ulong pktnum,c,serial; ushort attr; uchar fromname[36],toname[36],subject[72],datetime[20],origin[80]; uchar 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((uchar *)args[ARG_FROMADDR].data,&from4d))) { printf("Invalid address \"%s\"\n",(uchar *)args[ARG_FROMADDR].data); osEnd(); exit(OS_EXIT_ERROR); } } if(args[ARG_TOADDR].data) { if(!(Parse4D((uchar *)args[ARG_TOADDR].data,&to4d))) { printf("Invalid address \"%s\"\n",(uchar *)args[ARG_TOADDR].data); osEnd(); exit(OS_EXIT_ERROR); } } Copy4D(&pktfrom4d,&from4d); Copy4D(&pktto4d,&to4d); if(args[ARG_PKTFROMADDR].data) { if(!(Parse4D((uchar *)args[ARG_PKTFROMADDR].data,&pktfrom4d))) { printf("Invalid address \"%s\"\n",(uchar *)args[ARG_PKTFROMADDR].data); osEnd(); exit(OS_EXIT_ERROR); } } if(args[ARG_PKTTOADDR].data) { if(!(Parse4D((uchar *)args[ARG_PKTTOADDR].data,&pktto4d))) { printf("Invalid address \"%s\"\n",(uchar *)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,(uchar *)args[ARG_FROMNAME].data,36); if(args[ARG_TONAME].data) mystrncpy(toname,(uchar *)args[ARG_TONAME].data,36); if(args[ARG_SUBJECT].data) mystrncpy(subject,(uchar *)args[ARG_SUBJECT].data,72); if(args[ARG_ORIGIN].data) mystrncpy(origin,(uchar *)args[ARG_ORIGIN].data,80); MakeFidoDate(t,datetime); /* Create pkt file */ serial=0; do { t=time(NULL); pktnum = (t<<8) + serial; serial++; sprintf(pktname,"%08lx.pkt",pktnum); MakeFullPath(args[ARG_DIR].data,pktname,fullname,200); } while(osExists(fullname)); if(!(ofh=osOpen(fullname,MODE_NEWFILE))) { ulong 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 %ld\x0d",from4d.Point); if(to4d.Point) osFPrintf(ofh,"\x01" "TOPT %ld\x0d",to4d.Point); osFPrintf(ofh,"\x01" "INTL %lu:%lu/%lu %lu:%lu/%lu\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 %08lx\x0d", from4d.Zone,from4d.Net,from4d.Node,from4d.Point,pktnum); } if(args[ARG_TEXT].data) { printf("Appending %s...\n",(uchar *)args[ARG_TEXT].data); if(!(ifh=osOpen((uchar *)args[ARG_TEXT].data,MODE_OLDFILE))) { ulong err=osError(); printf("Unable to open \"%s\" for reading\n",(uchar *)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); } crashmail-0.71/src/tools/crashlistout.c0100644000000000000000000003415507762222060016735 0ustar rootroot#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define VERSION "1.0" #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 uchar *type_names[] = { "Crash", "Direct", "Normal", "Hold", "Request" }; ulong TotalFiles=0; ulong TotalBytes=0; ulong TotalRequests=0; struct fileentry { struct fileentry *Next; struct Node4D Node; uchar file[100]; uchar dir[100]; ulong size; time_t date; ulong type; bool flow; }; struct Node4DPat { uchar Zone[10]; uchar Net[10]; uchar Node[10]; uchar Point[10]; }; uchar *cfg_Dir; ulong 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 CrashMail) */ bool Parse4DPat(uchar *buf, struct Node4DPat *node) { ulong c=0,tempc=0; uchar 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;cZone,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(uchar *pat,ushort num) { uchar buf[10],c; sprintf(buf,"%u",num); if(pat[0]==0) return(0); for(c=0;cZone!=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 CrashMail */ char *unit(long i) { static char buf[20]; if ((i>10000000)||(i<-10000000)) sprintf(buf,"%luM",i/(1024*1024)); else if ((i>10000)||(i<-10000)) sprintf(buf,"%luK",i/1024); else sprintf(buf,"%lu",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 */ uchar *PrintNode(struct Node4D *node) { static uchar buf[50]; Print4D(node,buf); return(buf); } uchar *PrintDate(time_t date) { static uchar buf[50]; struct tm *tp; uchar *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); } uchar *PrintFlowSize(struct fileentry *fe) { static uchar buf[50]; uchar fullfile[200],line[200]; osFile os; struct osFileEntry *osfe; ulong 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/%lu",unit(bytes),files); return(buf); } void DisplayFlowContents(struct fileentry *fe) { uchar size[40],*todo; uchar 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,unit(osfe->Size)); osFree(osfe); } printf(" %-39.39s %10s %s\n",line,size,todo); } } osClose(os); } printf("\n"); } uchar *PrintReqNums(struct fileentry *fe) { static uchar buf[50]; uchar fullfile[200],line[200]; osFile os; ulong 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,"-/%lu",reqs); return(buf); } void DisplayReqContents(struct fileentry *fe) { uchar 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) { uchar 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; ulong 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(uchar *dir,uchar *file,ulong type,struct Node4D *boss,bool flow) { struct osFileEntry *fe; struct fileentry *entry; struct Node4D n4d; uchar buf[200]; uchar buf2[200]; ulong 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; uchar *scandir_dir; void scandirfunc(uchar *file) { uchar *extptr; ulong hex; if(strlen(file) != 12) return; extptr=&file[strlen(file)-4]; if(stricmp(extptr,".PNT")==0 && !scandir_boss) { uchar 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) { uchar *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=(uchar *)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((uchar *)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((uchar *)args[ARG_PATTERN].data,&cfg_Pattern)) { printf("Invalid node pattern \"%s\"\n",(uchar *)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)) { ulong 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 %lu files to send, %lu requests.\n",unit(TotalBytes),TotalFiles,TotalRequests); } else { printf("Outbound directory is empty.\n"); } jbFreeList(&list); exit(OS_EXIT_OK); } crashmail-0.71/src/tools/crashmaint.c0100644000000000000000000005234707762222130016343 0ustar rootroot#include #include #include #include #include #include #define NO_TYPEDEF_UCHAR #define NO_TYPEDEF_ULONG #define NO_TYPEDEF_USHORT #include #include #include #include #include #include #include #include #include #include #include #include #define VERSION "1.2" #ifdef PLATFORM_AMIGA uchar *ver="$VER: CrashMaint "VERSION" ("__COMMODORE_DATE__")"; #endif struct Area { struct Area *Next; uchar Tagname[80]; uchar Path[80]; uchar Messagebase[20]; ulong KeepNum,KeepDays; }; struct jbList AreaList; struct Messagebase { uchar *Name; bool (*processfunc)(struct Area *area,bool maint,bool pack,bool verbose); }; #ifdef MSGBASE_MSG bool ProcessAreaMSG(struct Area *area,bool maint, bool pack, bool verbose); #endif #ifdef MSGBASE_JAM bool ProcessAreaJAM(struct Area *area,bool maint, bool pack, bool verbose); #endif struct Messagebase Messagebases[] = { #ifdef MSGBASE_JAM { "JAM", ProcessAreaJAM }, #endif #ifdef MSGBASE_MSG { "MSG", ProcessAreaMSG }, #endif { NULL, NULL } }; #define ARG_MAINT 0 #define ARG_PACK 1 #define ARG_VERBOSE 2 #define ARG_SETTINGS 3 #define ARG_PATTERN 4 struct argument args[] = { { ARGTYPE_BOOL, "MAINT", 0, NULL }, { ARGTYPE_BOOL, "PACK", 0, NULL }, { ARGTYPE_BOOL, "VERBOSE", 0, NULL }, { ARGTYPE_STRING, "SETTINGS", 0, NULL }, { ARGTYPE_STRING, "PATTERN", 0, NULL }, { ARGTYPE_END, NULL, 0, 0 } }; bool ctrlc; void breakfunc(int x) { ctrlc=TRUE; } /******************** *.msg *********************/ #ifdef MSGBASE_MSG struct Msg { struct Msg *Next; ulong Num,NewNum,Day; }; struct jbList MsgList; int Compare(const void *a1,const void *a2) { struct Msg **m1,**m2; m1=(struct Msg **)a1; m2=(struct Msg **)a2; if((*m1)->Num > (*m2)->Num) return(1); if((*m1)->Num < (*m2)->Num) return(-1); return(0); } bool Sort(struct jbList *list) { struct Msg *msg,**buf,**work; ulong nc; nc=0; for(msg=(struct Msg *)list->First;msg;msg=msg->Next) nc++; if(nc == 0) return(TRUE); if(!(buf=(struct Msg **)osAlloc(nc*sizeof(struct StatsNode *)))) return(FALSE); work=buf; for(msg=(struct Msg *)list->First;msg;msg=msg->Next) *work++=msg; qsort(buf,nc,4,Compare); jbNewList(list); for(work=buf;nc--;) jbAddNode(list,(struct jbNode *)*work++); osFree(buf); return(TRUE); } void MakeFidoDate(time_t tim,uchar *dest) { struct tm *tp; time_t t; uchar *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); } uchar *scanfuncarea; bool nomem; void scanfunc(uchar *str) { uchar buf[200]; struct osFileEntry *fe; ulong num,day; struct Msg *msg; if(strlen(str) < 5) return; if(stricmp(&str[strlen(str)-4],".msg")!=0) return; if(atol(str) < 2) return; MakeFullPath(scanfuncarea,str,buf,200); if(!(fe=osGetFileEntry(buf))) return; num=atol(str); day=fe->Date / (24*60*60); osFree(fe); if(!(msg=(struct Msg *)osAlloc(sizeof(struct Msg)))) { nomem=TRUE; return; } jbAddNode(&MsgList,(struct jbNode *)msg); msg->Num=num; msg->Day=day; } bool ProcessAreaMSG(struct Area *area,bool maint, bool pack, bool verbose) { ulong today,num,del,highwater,oldhighwater; struct Msg *msg; uchar buf[200],newbuf[200],buf2[100]; struct StoredMsg StoredMsg; osFile fh; highwater=0; oldhighwater=0; jbNewList(&MsgList); printf("Processing %s...\n",area->Tagname); scanfuncarea=area->Path; if(!(osScanDir(area->Path,scanfunc))) { ulong err=osError(); printf(" Error: Couldn't scan directory %s\n",area->Path); printf(" Error: %s\n",osErrorMsg(err)); jbFreeList(&MsgList); return(TRUE); } if(nomem) { printf("Out of memory\n"); jbFreeList(&MsgList); return(FALSE); } if(!Sort(&MsgList)) { printf("Out of memory\n"); jbFreeList(&MsgList); return(FALSE); } if(!MsgList.First) { printf(" Area is empty\n"); return(TRUE); } if(ctrlc) { jbFreeList(&MsgList); return(TRUE); } MakeFullPath(area->Path,"1.msg",buf,200); if((fh=osOpen(buf,MODE_OLDFILE))) { if(osRead(fh,&StoredMsg,sizeof(struct StoredMsg))==sizeof(struct StoredMsg)) { highwater=StoredMsg.ReplyTo; oldhighwater=StoredMsg.ReplyTo; } osClose(fh); } if(maint && area->KeepNum!=0) { num=0; for(msg=(struct Msg *)MsgList.First;msg;msg=msg->Next) num++; msg=(struct Msg *)MsgList.First; del=0; while(num>area->KeepNum && !ctrlc) { while(msg->Num==0) msg=msg->Next; sprintf(buf2,"%lu.msg",msg->Num); MakeFullPath(area->Path,buf2,buf,200); if(msg->Num == highwater) highwater=0; if(verbose) printf(" Deleting message #%lu by number\n",msg->Num); osDelete(buf); msg->Num=0; num--; del++; } if(ctrlc) { jbFreeList(&MsgList); return(TRUE); } printf(" %lu messages deleted by number, %lu messages left\n",del,num); } if(maint && area->KeepDays!=0) { del=0; num=0; today=time(NULL) / (24*60*60); for(msg=(struct Msg *)MsgList.First;msg && !ctrlc;msg=msg->Next) { if(today - msg->Day > area->KeepDays && msg->Num!=0) { sprintf(buf2,"%lu.msg",msg->Num); MakeFullPath(area->Path,buf2,buf,200); if(msg->Num == highwater) highwater=0; if(verbose) printf(" Deleting message #%lu by date\n",msg->Num); osDelete(buf); msg->Num=0; del++; } else { num++; } } if(ctrlc) { jbFreeList(&MsgList); return(TRUE); } printf(" %lu messages deleted by date, %lu messages left\n",del,num); } if(pack) { num=2; msg=(struct Msg *)MsgList.First; while(msg && !ctrlc) { while(msg && msg->Num==0) msg=msg->Next; if(msg) { msg->NewNum=num++; msg=msg->Next; } } for(msg=(struct Msg *)MsgList.First;msg && !ctrlc;msg=msg->Next) if(msg->Num!=0 && msg->Num!=msg->NewNum) { sprintf(buf2,"%lu.msg",msg->Num); MakeFullPath(area->Path,buf2,buf,200); sprintf(buf2,"%lu.msg",msg->NewNum); MakeFullPath(area->Path,buf2,newbuf,200); if(highwater == msg->Num) highwater=msg->NewNum; if(verbose) printf(" Renaming message %lu to %lu\n",msg->Num,msg->NewNum); osRename(buf,newbuf); } if(ctrlc) { jbFreeList(&MsgList); return(TRUE); } printf(" Area renumbered\n"); } jbFreeList(&MsgList); if(highwater!=oldhighwater) { strcpy(StoredMsg.From,"CrashMail II"); strcpy(StoredMsg.To,"All"); strcpy(StoredMsg.Subject,"HighWater mark"); MakeFidoDate(time(NULL),StoredMsg.DateTime); StoredMsg.TimesRead=0; StoredMsg.DestNode=0; StoredMsg.OrigNode=0; StoredMsg.Cost=0; StoredMsg.OrigNet=0; StoredMsg.DestNet=0; StoredMsg.DestZone=0; StoredMsg.OrigZone=0; StoredMsg.OrigPoint=0; StoredMsg.DestPoint=0; StoredMsg.ReplyTo=highwater; StoredMsg.Attr=FLAG_SENT | FLAG_PVT; StoredMsg.NextReply=0; MakeFullPath(area->Path,"1.msg",buf,200); if((fh=osOpen(buf,MODE_NEWFILE))) { osWrite(fh,&StoredMsg,sizeof(struct StoredMsg)); osWrite(fh,"",1); osClose(fh); } } return(TRUE); } #endif /*************************** JAM ************************/ #ifdef MSGBASE_JAM long jam_utcoffset = 0xbaadf00d; bool ProcessAreaJAM(struct Area *area,bool maint, bool pack, bool verbose) { ulong today,active,basenum,total,del,num,day; s_JamBase *Base_PS,*NewBase_PS; s_JamBaseHeader BaseHeader_S; s_JamMsgHeader Header_S; s_JamSubPacket* SubPacket_PS; int res,res1,res2; uchar buf[200],oldname[200],tmpname[200]; bool firstwritten; uchar *msgtext; /* Some timezone tricks */ if(jam_utcoffset == 0xbaadf00d) { time_t t1,t2; struct tm *tp; t1=time(NULL); tp=gmtime(&t1); tp->tm_isdst=-1; t2=mktime(tp); jam_utcoffset=t2-t1; } printf("Processing %s...\n",area->Tagname); if(JAM_OpenMB(area->Path,&Base_PS)) { printf(" Failed to open messagebase \"%s\"\n",area->Path); return(TRUE); } if(JAM_LockMB(Base_PS,10)) { printf(" Timeout when trying to lock messagebase \"%s\"\n",area->Path); JAM_CloseMB(Base_PS); return(TRUE); } if(JAM_ReadMBHeader(Base_PS,&BaseHeader_S)) { printf(" Failed to read header of messagebase \"%s\"\n",area->Path); JAM_UnlockMB(Base_PS); JAM_CloseMB(Base_PS); return(TRUE); } if(JAM_GetMBSize(Base_PS,&total)) { printf(" Failed to get size of messagebase \"%s\"\n",area->Path); JAM_UnlockMB(Base_PS); JAM_CloseMB(Base_PS); return(TRUE); } basenum=BaseHeader_S.BaseMsgNum; active=BaseHeader_S.ActiveMsgs; if(total == 0) { printf(" Area is empty\n"); JAM_UnlockMB(Base_PS); JAM_CloseMB(Base_PS); return(TRUE); } if(maint && area->KeepNum!=0) { num=0; del=0; while(num < total && active > area->KeepNum && !ctrlc) { res=JAM_ReadMsgHeader(Base_PS,num,&Header_S,NULL); if(res == 0) { /* Read success */ if(!(Header_S.Attribute & MSG_DELETED)) { /* Not already deleted */ if(verbose) printf(" Deleting message #%lu by number\n",basenum+num); Header_S.Attribute |= MSG_DELETED; JAM_ChangeMsgHeader(Base_PS,num,&Header_S); BaseHeader_S.ActiveMsgs--; JAM_WriteMBHeader(Base_PS,&BaseHeader_S); active--; del++; } } num++; } if(ctrlc) { JAM_UnlockMB(Base_PS); JAM_CloseMB(Base_PS); return(TRUE); } printf(" %lu messages deleted by number, %lu messages left\n",del,active); } if(maint && area->KeepDays!=0) { del=0; num=0; today=(time(NULL)-jam_utcoffset) / (24*60*60); while(num < total && !ctrlc) { res=JAM_ReadMsgHeader(Base_PS,num,&Header_S,NULL); if(res == 0) { /* Read success */ day=Header_S.DateReceived / (24*60*60); if(day == 0) day=Header_S.DateProcessed / (24*60*60); if(day == 0) day=Header_S.DateWritten / (24*60*60); if(today-day > area->KeepDays && !(Header_S.Attribute & MSG_DELETED)) { /* Not already deleted and too old*/ if(verbose) printf(" Deleting message #%lu by date\n",basenum+num); Header_S.Attribute |= MSG_DELETED; JAM_ChangeMsgHeader(Base_PS,num,&Header_S); BaseHeader_S.ActiveMsgs--; JAM_WriteMBHeader(Base_PS,&BaseHeader_S); del++; active--; } } num++; } if(ctrlc) { JAM_UnlockMB(Base_PS); JAM_CloseMB(Base_PS); return(TRUE); } printf(" %lu messages deleted by date, %lu messages left\n",del,active); } if(pack) { strcpy(buf,area->Path); strcat(buf,".cmtemp"); if(JAM_CreateMB(buf,1,&NewBase_PS)) { printf(" Failed to create new messagebase \"%s\"\n",buf); JAM_UnlockMB(Base_PS); JAM_CloseMB(Base_PS); return(TRUE); } if(JAM_LockMB(NewBase_PS,10)) { printf(" Timeout when trying to lock messagebase \"%s\"\n",buf); JAM_UnlockMB(Base_PS); JAM_CloseMB(Base_PS); JAM_CloseMB(NewBase_PS); JAM_RemoveMB(NewBase_PS,buf); return(TRUE); } /* Copy messages */ del=0; num=0; firstwritten=FALSE; BaseHeader_S.ActiveMsgs=0; while(num < total && !ctrlc) { res=JAM_ReadMsgHeader(Base_PS,num,&Header_S,NULL); if(res) { if(res == JAM_NO_MESSAGE) { if(firstwritten) { JAM_AddEmptyMessage(NewBase_PS); } else { BaseHeader_S.BaseMsgNum++; del++; } } else { printf(" Failed to read message %ld, cannot pack messagebase\n",num+basenum); JAM_UnlockMB(Base_PS); JAM_CloseMB(Base_PS); JAM_UnlockMB(NewBase_PS); JAM_CloseMB(NewBase_PS); JAM_RemoveMB(NewBase_PS,buf); return(TRUE); } } else { if(Header_S.Attribute & MSG_DELETED) { if(firstwritten) { JAM_AddEmptyMessage(NewBase_PS); } else { BaseHeader_S.BaseMsgNum++; del++; } } else { if(!firstwritten) { /* Set basenum */ res=JAM_WriteMBHeader(NewBase_PS,&BaseHeader_S); if(res) { printf(" Failed to write messagebase header, cannot pack messagebase\n"); JAM_UnlockMB(Base_PS); JAM_CloseMB(Base_PS); JAM_UnlockMB(NewBase_PS); JAM_CloseMB(NewBase_PS); JAM_RemoveMB(NewBase_PS,buf); return(TRUE); } firstwritten=TRUE; } /* Read header with all subpackets*/ res=JAM_ReadMsgHeader(Base_PS,num,&Header_S,&SubPacket_PS); if(res) { printf(" Failed to read message %ld, cannot pack messagebase\n",num+basenum); JAM_UnlockMB(Base_PS); JAM_CloseMB(Base_PS); JAM_UnlockMB(NewBase_PS); JAM_CloseMB(NewBase_PS); JAM_RemoveMB(NewBase_PS,buf); return(TRUE); } /* Read message text */ msgtext=NULL; if(Header_S.TxtLen) { if(!(msgtext=osAlloc(Header_S.TxtLen))) { printf("Out of memory\n"); JAM_DelSubPacket(SubPacket_PS); JAM_UnlockMB(Base_PS); JAM_CloseMB(Base_PS); JAM_UnlockMB(NewBase_PS); JAM_CloseMB(NewBase_PS); JAM_RemoveMB(NewBase_PS,buf); return(FALSE); } res=JAM_ReadMsgText(Base_PS,Header_S.TxtOffset,Header_S.TxtLen,msgtext); if(res) { printf(" Failed to read message %ld, cannot pack messagebase\n",num+basenum); JAM_DelSubPacket(SubPacket_PS); JAM_UnlockMB(Base_PS); JAM_CloseMB(Base_PS); JAM_UnlockMB(NewBase_PS); JAM_CloseMB(NewBase_PS); JAM_RemoveMB(NewBase_PS,buf); return(TRUE); } } /* Write new message */ res=JAM_AddMessage(NewBase_PS,&Header_S,SubPacket_PS,msgtext,Header_S.TxtLen); if(msgtext) osFree(msgtext); JAM_DelSubPacket(SubPacket_PS); BaseHeader_S.ActiveMsgs++; if(res) { printf(" Failed to copy message %ld (disk full?), cannot pack messagebase\n",num+basenum); JAM_UnlockMB(Base_PS); JAM_CloseMB(Base_PS); JAM_UnlockMB(NewBase_PS); JAM_CloseMB(NewBase_PS); JAM_RemoveMB(NewBase_PS,buf); return(TRUE); } } } num++; } /* Write back header */ BaseHeader_S.ModCounter++; res=JAM_WriteMBHeader(NewBase_PS,&BaseHeader_S); if(res) { printf(" Failed to write messagebase header, cannot pack messagebase\n"); JAM_UnlockMB(Base_PS); JAM_CloseMB(Base_PS); JAM_UnlockMB(NewBase_PS); JAM_CloseMB(NewBase_PS); JAM_RemoveMB(NewBase_PS,buf); return(TRUE); } JAM_UnlockMB(Base_PS); JAM_CloseMB(Base_PS); JAM_UnlockMB(NewBase_PS); JAM_CloseMB(NewBase_PS); if(ctrlc) { JAM_RemoveMB(NewBase_PS,buf); return(TRUE); } /* This could not be done with JAMLIB... */ sprintf(oldname,"%s%s",area->Path,EXT_HDRFILE); sprintf(tmpname,"%s.cmtemp%s",area->Path,EXT_HDRFILE); res1=osDelete(oldname); res2=osRename(tmpname,oldname); if(res1 && res2) { sprintf(oldname,"%s%s",area->Path,EXT_TXTFILE); sprintf(tmpname,"%s.cmtemp%s",area->Path,EXT_TXTFILE); res1=osDelete(oldname); res2=osRename(tmpname,oldname); } if(res1 && res2) { sprintf(oldname,"%s%s",area->Path,EXT_IDXFILE); sprintf(tmpname,"%s.cmtemp%s",area->Path,EXT_IDXFILE); res1=osDelete(oldname); res2=osRename(tmpname,oldname); } if(res1 && res2) { sprintf(oldname,"%s%s",area->Path,EXT_LRDFILE); sprintf(tmpname,"%s.cmtemp%s",area->Path,EXT_LRDFILE); /* Keep lastread file */ res2=osDelete(tmpname); } if(!res1 || !res2) { printf(" Failed to update area. The area might be in use by another program.\n"); return(FALSE); } printf(" %ld deleted messages removed from messagebase\n",del); } else { JAM_UnlockMB(Base_PS); JAM_CloseMB(Base_PS); } return(TRUE); } #endif /************************** end of messagebases *******************/ uchar cfgbuf[4000]; bool ReadConfig(uchar *file) { osFile fh; uchar cfgword[20]; uchar tag[80],aka[80],path[80],mb[20]; struct Area *tmparea,*LastArea; ulong jbcpos; if(!(fh=osOpen(file,MODE_OLDFILE))) { ulong err=osError(); printf("Failed to open file %s for reading\n",file); printf("Error: %s\n",osErrorMsg(err)); return(FALSE); } LastArea=NULL; while(osFGets(fh,cfgbuf,4000)) { jbcpos=0; jbstrcpy(cfgword,cfgbuf,20,&jbcpos); if(stricmp(cfgword,"KEEPDAYS")==0 && LastArea) { if(jbstrcpy(tag,cfgbuf,80,&jbcpos)) LastArea->KeepDays=atol(tag); } if(stricmp(cfgword,"KEEPNUM")==0 && LastArea) { if(jbstrcpy(tag,cfgbuf,80,&jbcpos)) LastArea->KeepNum=atol(tag); } if(stricmp(cfgword,"AREA")==0 || stricmp(cfgword,"NETMAIL")==0 || stricmp(cfgword,"LOCALAREA")==0) { jbstrcpy(tag,cfgbuf,80,&jbcpos); jbstrcpy(aka,cfgbuf,80,&jbcpos); if(stricmp(tag,"DEFAULT")!=0 && strnicmp(tag,"DEFAULT_",8)!=0) { if(jbstrcpy(mb,cfgbuf,20,&jbcpos)) { jbstrcpy(path,cfgbuf,80,&jbcpos); if(!(tmparea=(struct Area *)osAllocCleared(sizeof(struct Area)))) { printf("Out of memory\n"); osClose(fh); return(FALSE); } jbAddNode(&AreaList,(struct jbNode *)tmparea); LastArea=tmparea; strcpy(tmparea->Tagname,tag); strcpy(tmparea->Messagebase,mb); strcpy(tmparea->Path,path); } } } } osClose(fh); return(TRUE); } int main(int argc, char **argv) { struct Area *area; uchar *cfg; bool maint,pack,verbose; int i; 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); } jbNewList(&AreaList); maint=FALSE; pack=FALSE; verbose=FALSE; if(args[ARG_MAINT].data) maint=TRUE; if(args[ARG_PACK].data) pack=TRUE; if(args[ARG_VERBOSE].data) verbose=TRUE; if(!maint && !pack) { printf("Nothing to do.\n"); osEnd(); exit(OS_EXIT_OK); } if(args[ARG_PATTERN].data) { if(!(osCheckPattern((uchar *)args[ARG_PATTERN].data))) { printf("Invalid pattern \"%s\"\n",(uchar *)args[ARG_PATTERN].data); osEnd(); exit(OS_EXIT_ERROR); } } cfg=getenv(OS_CONFIG_VAR); if(!cfg) cfg=OS_CONFIG_NAME; if(args[ARG_SETTINGS].data) cfg=(uchar *)args[ARG_SETTINGS].data; if(!(ReadConfig(cfg))) { jbFreeList(&AreaList); osEnd(); exit(OS_EXIT_ERROR); } for(area=(struct Area *)AreaList.First;area && !ctrlc;area=area->Next) { bool match; match=FALSE; if(!args[ARG_PATTERN].data) match=TRUE; else if(osMatchPattern((uchar *)args[ARG_PATTERN].data,area->Tagname)) match=TRUE; if(match) { for(i=0;Messagebases[i].Name;i++) if(stricmp(Messagebases[i].Name,area->Messagebase)==0) break; if(Messagebases[i].processfunc) { if(!Messagebases[i].processfunc(area,maint,pack,verbose)) exit(OS_EXIT_ERROR); } else { printf("Cannot process area %s, messagebase %s not supported by CrashMaint\n", area->Tagname, area->Messagebase); } } } if(ctrlc) printf("*** User Break ***\n"); jbFreeList(&AreaList); osEnd(); exit(OS_EXIT_OK); } crashmail-0.71/src/tools/crashexport.c0100644000000000000000000002063007762222211016542 0ustar rootroot#include #include #include #include #include #include #include #include #include #include #include #include #define VERSION "1.0" #ifdef PLATFORM_AMIGA uchar *ver="$VER: CrashExport " VERSION " " __AMIGADATE__; #endif bool diskfull; uchar cfgbuf[4000]; #define AREATYPE_NETMAIL 1 #define AREATYPE_ECHOMAIL 2 #define AREATYPE_DEFAULT 3 #define AREATYPE_BAD 4 #define AREATYPE_LOCAL 5 uchar tagname[100],desc[100],msgbase[10],path[100],export[1000],aka[50]; uchar 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(uchar group,uchar *node) { int c; for(c=0;c 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((uchar *)args[ARG_FORMAT].data,"areasbbs")==0) { format=FORMAT_AREASBBS; } else if(stricmp((uchar *)args[ARG_FORMAT].data,"forward")==0) { format=FORMAT_FORWARD; } else if(stricmp((uchar *)args[ARG_FORMAT].data,"forwardnodesc")==0) { format=FORMAT_FORWARDNODESC; } else if(stricmp((uchar *)args[ARG_FORMAT].data,"golded")==0) { format=FORMAT_GOLDED; } else if(stricmp((uchar *)args[ARG_FORMAT].data,"timed")==0) { format=FORMAT_TIMED; } else { printf("Unknown format \"%s\"\n",(uchar *)args[ARG_FORMAT].data); osEnd(); exit(OS_EXIT_ERROR); } if(!(ifh=osOpen(args[ARG_PREFSFILE].data,MODE_OLDFILE))) { ulong 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))) { ulong 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); } crashmail-0.71/src/tools/crashstats.c0100644000000000000000000004100407762222117016362 0ustar rootroot#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define VERSION "1.0" #define COPYRIGHT "1998" #ifdef PLATFORM_AMIGA uchar *ver="$VER: CrashStats "VERSION" ("__COMMODORE_DATE__")"; #endif #define STATS_IDENTIFIER "CST3" struct DiskAreaStats { uchar Tagname[80]; struct Node4D Aka; uchar Group; uchar fill_to_make_even; /* Just ignore this one */ ulong TotalTexts; ushort Last8Days[8]; ulong Dupes; time_t FirstTime; time_t LastTime; }; struct DiskNodeStats { struct Node4D Node; ulong GotNetmails; ulong GotNetmailBytes; ulong SentNetmails; ulong SentNetmailBytes; ulong GotEchomails; ulong GotEchomailBytes; ulong SentEchomails; ulong SentEchomailBytes; ulong Dupes; time_t FirstTime; }; struct StatsNode { struct StatsNode *Next; uchar Tagname[80]; ulong Average; ulong Total; ulong Dupes; time_t FirstTime; time_t LastTime; ushort Last8Days[8]; }; struct NodeStatsNode { struct NodeStatsNode *Next; struct Node4D Node; ulong GotNetmails; ulong GotNetmailBytes; ulong SentNetmails; ulong SentNetmailBytes; ulong GotEchomails; ulong GotEchomailBytes; ulong SentEchomails; ulong SentEchomailBytes; ulong Dupes; ulong 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,uchar sortmode) { ulong 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,4,CompareAlpha); break; case 't': qsort(buf,nc,4,CompareTotal); break; case 'm': qsort(buf,nc,4,CompareMsgsDay); break; case 'd': qsort(buf,nc,4,CompareFirstTime); break; case 'l': qsort(buf,nc,4,CompareLastTime); break; case 'u': qsort(buf,nc,4,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; ulong 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,4,CompareNodes); jbNewList(list); for(work=buf;nc--;) jbAddNode(list,(struct jbNode *)*work++); osFree(buf); return(TRUE); } char *unit(long i) { static char buf[40]; if ((i>10000000)||(i<-10000000)) sprintf(buf,"%ld MB",i/(1024*1024)); else if ((i>10000)||(i<-10000)) sprintf(buf,"%ld KB",i/1024); else sprintf(buf,"%ld bytes",i); return buf; } bool CheckFlags(uchar group,uchar *node) { int c; for(c=0;c 7) days=7; sum=0; for(c=1;c 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(((uchar *)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\n"); if(!(fh=osOpen(args[ARG_FILE].data,MODE_OLDFILE))) { ulong 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(ulong)); 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(ulong)); c=0; if(!args[ARG_NOAREAS].data) { while(cTagname,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(ushort)); 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(cNode,&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(ctm_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 : %5ld\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 %lu areas",areas); printf("%-33.33s %4d %4d %4d %4d %4d %4d %4d : %5ld\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,""); } 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,""); } 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("%-30.30s %-9.9s %-9.9s %7ld %7ld %7ld\n",sn->Tagname,date,date2,sn->Total,sn->Average,sn->Dupes); } } if(!ctrlc) { printf("============================================================================\n"); sprintf(buf,"Totally in all %lu areas",areas); printf("%-42s %7ld %7ld %7ld\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,""); } 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: %lu/%s\n",nsn->SentNetmails,unit(nsn->SentNetmailBytes)); printf(" Received netmails: %lu/%s\n",nsn->GotNetmails,unit(nsn->GotNetmailBytes)); printf(" Sent echomails: %lu/%s\n",nsn->SentEchomails,unit(nsn->SentEchomailBytes)); printf(" Received echomails: %lu/%s\n",nsn->GotEchomails,unit(nsn->GotEchomailBytes)); printf(" Dupes: %lu\n",nsn->Dupes); printf("\n"); } } if(ctrlc) { printf("*** Break\n"); } else { printf("\n"); } jbFreeList(&StatsList); jbFreeList(&NodesList); osEnd(); exit(OS_EXIT_OK); } crashmail-0.71/src/tools/crashlist.c0100644000000000000000000001372407763212354016212 0ustar rootroot#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define VERSION "1.0" #ifdef PLATFORM_AMIGA uchar *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 { ushort zone,net,node,point,region,hub; ulong offset; }; bool nomem,diskfull; void putuword(uchar *buf,ulong offset,ushort num) { buf[offset]=num%256; buf[offset+1]=num/256; } void putulong(uchar *buf,ulong offset,ulong 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) { uchar 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)); } uchar nlname[100]; uchar *findfile,*finddir; time_t newest; bool isnodelistending(uchar *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(uchar *file) { uchar 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(uchar *dir,uchar *file,uchar *dest) { MakeFullPath(dir,file,dest,500); if(osExists(dest)) return(TRUE); nlname[0]=0; newest=0; findfile=file; finddir=dir; if(!osScanDir(dir,scandirfunc)) { ulong 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(uchar *dir,uchar *file,osFile ifh,ushort defzone) { struct idx idx; uchar buf[500]; osFile nfh; if(!FindList(dir,file,buf)) return; if(!(nfh=osOpen(buf,MODE_OLDFILE))) { ulong err=osError(); printf("Failed to read %s\n",buf); printf("Error: %s\n",osErrorMsg(err)); return; } strcpy(buf,(uchar *)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; uchar *dir,buf[200],cfgbuf[200],file[100]; ulong 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=(uchar *)args[ARG_DIRECTORY].data; MakeFullPath(dir,"cmnodelist.prefs",buf,200); if(!(lfh=osOpen(buf,MODE_OLDFILE))) { ulong 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))) { ulong 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 */ crashmail-0.71/src/oslib_os2/0040755000000000000000000000000007300264670014574 5ustar rootrootcrashmail-0.71/src/oslib_os2/os.c0100644000000000000000000000016607300264670015361 0ustar rootroot#include #include bool osInit(void) { return(TRUE); } void osEnd(void) { } crashmail-0.71/src/oslib_os2/os_os2.h0100644000000000000000000000130507300264670016145 0ustar rootroot#include #include #include bool osInit(void); void osEnd(void); typedef unsigned short UINT16; /* Unsigned 16-bit integer */ #define OS_EXIT_ERROR 10 #define OS_EXIT_OK 0 #define OS_PLATFORM_NAME "2" #define OS_CURRENT_DIR "." #define OS_PATH_CHARS "\\" #define OS_CONFIG_NAME "crashmail.prefs" #define OS_CONFIG_VAR "CMCONFIGFILE" /* 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" */ crashmail-0.71/src/oslib_os2/Makefile0100644000000000000000000000077507300264670016242 0ustar rootrootINCDIR = ../ CC = gcc -I $(INCDIR) -DPLATFORM_OS2 -Wall AR = ar -ru RM = del 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 crashmail-0.71/src/oslib_os2/osfile.c0100644000000000000000000000373207300264670016223 0ustar rootroot#include #include #include #include #include #include osFile osOpen(uchar *name,ulong 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); } ulong osRead(osFile os,void *buf,ulong bytes) { return fread(buf,1,bytes,(FILE *)os); } bool osPutChar(osFile os, uchar ch) { if(fputc(ch,(FILE *)os)==EOF) return(FALSE); return(TRUE); } bool osWrite(osFile os,const void *buf,ulong bytes) { if(fwrite(buf,1,bytes,(FILE *)os)!=bytes) return(FALSE); return(TRUE); } bool osPuts(osFile os,uchar *str) { if(fputs(str,(FILE *)os)==EOF) return(FALSE); return(TRUE); } ulong osFGets(osFile os,uchar *str,ulong 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 (ulong)strlen(s); } return(0); } ulong osFTell(osFile os) { return ftell((FILE *)os); } bool osFPrintf(osFile os,uchar *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,uchar *fmt,va_list args) { int res; res=vfprintf(os,fmt,args); if(!res) return(FALSE); return(TRUE); } void osSeek(osFile fh,ulong offset,short mode) { int md; if(mode == OFFSET_BEGINNING) md=SEEK_SET; if(mode == OFFSET_END) md=SEEK_END; fseek((FILE *)fh,offset,md); } crashmail-0.71/src/oslib_os2/osmisc.c0100644000000000000000000000355207300264670016237 0ustar rootroot#include #include #include #include #include #include #include #include #include #include #include /*#include */ #include #include #include #include void osSetComment(uchar *file,uchar *comment) { /* Modeled after * eatool.c (emx+gcc) -- Copyright (c) 1992-1995 by Eberhard Mattes * by Peter Karlsson 1999 */ char *buf; _ead ead; int size; ead = _ead_create(); if (!ead) return; size = strlen(comment); buf = malloc(size + 4); if (buf != NULL) { ((USHORT *)buf)[0] = EAT_ASCII; ((USHORT *)buf)[1] = size; memcpy(buf+4, comment, size); if (_ead_add(ead, ".SUBJECT", 0, buf, size + 4) >= 0) { _ead_write(ead, file, 0, _EAD_MERGE); } } free(buf); _ead_destroy(ead); } /* Returns -1 if dir was not found and errorlevel otherwise */ int osChDirExecute(uchar *dir,uchar *cmd) { char olddir[300]; int res; if(!getcwd(olddir,300)) return(-1); if(chdir(dir) != 0) return(-1); res=system(cmd); chdir(olddir); return(res); } int osExecute(uchar *cmd) { return system(cmd); } bool osExists(uchar *file) { struct stat st; if(stat(file,&st) == 0) return(TRUE); return(FALSE); } bool osMkDir(uchar *dir) { if(mkdir(dir, 0) != 0) return(FALSE); return(TRUE); } bool osRename(uchar *oldfile,uchar *newfile) { if(rename(oldfile,newfile) == 0) return(TRUE); return(FALSE); } bool osDelete(uchar *file) { if(remove(file) == 0) return(TRUE); return(FALSE); } void osSleep(int secs) { sleep(secs); } uchar *osErrorMsg(ulong errnum) { return (uchar *)strerror(errnum); } ulong osError(void) { return (ulong)errno; } crashmail-0.71/src/oslib_os2/ospattern.c0100644000000000000000000000114107300264670016751 0ustar rootroot#include #include #include #include bool osCheckPattern(uchar *pattern) { return(TRUE); } bool osMatchPattern(uchar *pattern,uchar *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(uchar *pat) { if(strchr(pat,'?') || strchr(pat,'*')) return(TRUE); return(FALSE); } crashmail-0.71/src/oslib_os2/osdir.c0100644000000000000000000000400307300264670016052 0ustar rootroot#include #include #include #include #include #include #include #include #include #include #include #include #include #include bool osReadDir(uchar *dirname,struct jbList *filelist,bool (*acceptfunc)(uchar *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(uchar *dirname,void (*func)(uchar *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(uchar *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); } crashmail-0.71/src/oslib_os2/osmem.c0100644000000000000000000000036107300264670016055 0ustar rootroot#include #include void *osAlloc(ulong size) { return malloc((size_t)size); } void *osAllocCleared(ulong size) { return calloc((size_t)size,1); } void osFree(void *buf) { free(buf); } crashmail-0.71/src/crashmail/0040755000000000000000000000000010073763256014651 5ustar rootrootcrashmail-0.71/src/crashmail/mb.c0100644000000000000000000000125207300264670015403 0ustar rootroot#include "crashmail.h" #ifdef MSGBASE_MSG #include "mb_msg.h" #endif #ifdef MSGBASE_JAM #include "mb_jam.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 { NULL, /* NULL here marks the end of the array */ NULL, 0, NULL, NULL, NULL, NULL, NULL } }; crashmail-0.71/src/crashmail/mb.h0100644000000000000000000000074507300264670015416 0ustar rootroot#ifndef MB_H #define MB_H #include "shared/types.h" #include "memmessage.h" #include "config.h" struct Messagebase { uchar *name; uchar *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,ulong max,bool (*handlefunc)(struct MemMessage *mm)); }; #endif crashmail-0.71/src/crashmail/nl.c0100644000000000000000000000116207054024066015415 0ustar rootroot#include "crashmail.h" #ifdef NODELIST_CMNL #include "nl_cmnl.h" #endif #ifdef NODELIST_V7P #include "nl_v7p.h" #endif struct Nodelist AvailNodelists[] = { #ifdef NODELIST_CMNL { "CMNL", "CrashMail 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 } }; crashmail-0.71/src/crashmail/nl.h0100644000000000000000000000046307007103274015422 0ustar rootroot#ifndef NL_H #define NL_H #include struct Nodelist { uchar *name; uchar *desc; bool (*nlStart)(uchar *errbuf); void (*nlEnd)(void); bool (*nlCheckNode)(struct Node4D *node); long (*nlGetHub)(struct Node4D *node); long (*nlGetRegion)(struct Node4D *node); }; #endif crashmail-0.71/src/crashmail/logwrite.c0100644000000000000000000000432207764163573016660 0ustar rootroot#include "crashmail.h" #ifdef OS_HAS_SYSLOG #include 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(uchar *logfile) { #ifdef OS_HAS_SYSLOG if(stricmp(logfile,"syslog")==0) { usesyslog=TRUE; openlog("CrashMail",0,LOG_USER); return(TRUE); } #endif if(!(logfh=osOpen(logfile,MODE_READWRITE))) { ulong 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); } uchar *categoryletters="-%=!/D+^?"; void LogWrite(ulong level,ulong category,uchar *fmt,...) { va_list args; time_t t; struct tm *tp; uchar *monthnames[]={"Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec","???"}; uchar 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;itm_mday, monthnames[tp->tm_mon], tp->tm_year%100, tp->tm_hour, tp->tm_min, tp->tm_sec); osVFPrintf(logfh,fmt,args); osFPrintf(logfh,"\n"); va_end(args); } crashmail-0.71/src/crashmail/logwrite.h0100644000000000000000000000054107300264670016646 0ustar rootroot#include #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(uchar *filename); void CloseLogfile(void); void LogWrite(ulong level,ulong category,uchar *fmt,...); crashmail-0.71/src/crashmail/outbound.c0100644000000000000000000005072507763201625016661 0ustar rootroot#include "crashmail.h" struct jbList ArcList; bool doAddFlow(uchar *filename,uchar *basename,uchar type,long mode); bool LockBasename(uchar *basename) { uchar buf[200]; osFile fp; strcpy(buf,basename); strcat(buf,".bsy"); if(osExists(buf)) return(FALSE); if(!(fp=osOpen(buf,MODE_NEWFILE))) { ulong 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(uchar *basename) { uchar buf[200]; strcpy(buf,basename); strcat(buf,".bsy"); osDelete(buf); } void MakeBaseName(struct Node4D *n4d,uchar *basename) { struct Aka *firstaka; struct Route *tmproute; bool samedomain; uchar *ospathchars; ulong num,c; uchar 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,".%03lx",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,".%03lx",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; uchar 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; uchar buf[200],buf2[200]; ulong 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(ulong num) { uchar name[20]; struct osFileEntry *fe; struct ConfigNode *cnode; sprintf(name,"%08lx.",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(ulong basenum,ulong num) { uchar name[20]; struct osFileEntry *fe; uchar *daynames[]={"su","mo","tu","we","th","fr","sa"}; sprintf(name,"%08lx.%s%ld",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,uchar *dest) { struct osFileEntry *fe,*foundfe; uchar ext[10]; ulong basenum; long suffix,newsuffix,day,i; uchar *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,"%08lx.%s%ld",basenum,daynames[newsuffix/10],newsuffix%10); if(stricmp(cnode->LastArcName,dest)!=0) { mystrncpy(cnode->LastArcName,dest,13); WriteIndex(); } } void DeleteZero(uchar *dir,struct jbList *arclist) { struct osFileEntry *fe,*fe2; uchar 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(uchar *name) { osFile fh; uchar buf[200],buf2[200]; char type; bool mode; ulong jbcpos; struct Node4D n4d; uchar basename[200]; if(!(fh=osOpen(name,MODE_OLDFILE))) { ulong 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(uchar *file,struct Node4D *n4d,char type,long mode) { uchar buf[200]; osFile fh; strcpy(buf,file); strcat(buf,".orphan"); if(!(fh=osOpen(buf,MODE_NEWFILE))) { ulong 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(uchar *filename,uchar *basename,uchar type,long mode) { uchar buf[200],letter,*prefix; osFile fh; 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))) { ulong 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); if(buf[0]=='#') strcpy(buf,&buf[1]); if(buf[0]=='~') strcpy(buf,&buf[1]); if(buf[0]=='^') strcpy(buf,&buf[1]); if(buf[0]=='-') strcpy(buf,&buf[1]); if(stricmp(buf,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(uchar *filename,struct Node4D *n4d,uchar type,long mode) { uchar 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(uchar *name) { uchar 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(uchar *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) { uchar basename[200],arcname[200],pktname[200],buf[200],buf2[200],*copybuf; ulong jbcpos,readlen; int c,res; struct Node4D n4d; char type; uchar 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: %lu",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: %lu",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=(uchar *)osAlloc(COPYBUFSIZE))) { nomem=TRUE; UnlockBasename(basename); return(FALSE); } if(!(ifh=osOpen(file,MODE_OLDFILE))) { ulong 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))) { ulong 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))) { ulong 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; uchar buf[200]; /* Orphan files */ LogWrite(3,ACTIONINFO,"Scanning for orphan files"); if(!(osReadDir(config.cfg_PacketDir,&ArcList,IsOrphan))) { ulong 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))) { ulong 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))) { ulong 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))) { ulong 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); } crashmail-0.71/src/crashmail/outbound.h0100644000000000000000000000033207300264670016647 0ustar rootroot#define FLOW_NONE 0 #define FLOW_TRUNC 1 #define FLOW_DELETE 2 bool ArchiveOutbound(void); void MakeBaseName(struct Node4D *n4d,uchar *basename); bool AddFlow(uchar *filename,struct Node4D *n4d,uchar type,long mode); crashmail-0.71/src/crashmail/memmessage.c0100644000000000000000000002556507764207223017152 0ustar rootroot#include "crashmail.h" bool mmAddNodes2DList(struct jbList *list,ushort net,ushort node) { /* Add a node to SEEN-BY list */ struct Nodes2D *tmplist; ushort num; /* Check if it already exists */ for(tmplist=(struct Nodes2D *)list->First;tmplist;tmplist=tmplist->Next) { for(num=0;numNodes;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,ushort net,ushort node) { /* Rem a node from SEEN-BY list */ struct Nodes2D *tmplist; ushort num; for(tmplist=(struct Nodes2D *)list->First;tmplist;tmplist=tmplist->Next) for(num=0;numNodes;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; ushort num; for(tmplist=(struct Nodes2D *)list->First;tmplist;tmplist=tmplist->Next) for(num=0;numNodes;num++) { if(Compare2DPat(pat,tmplist->Net[num],tmplist->Node[num])==0) { tmplist->Net[num]=0; tmplist->Node[num]=0; } } } bool mmAddPath(uchar *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,uchar *buf,ulong len) { struct TextChunk *chunk,*oldchunk; ulong 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 { ushort Net; ushort 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; ulong nodes=0; ulong 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;cNodes;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;cNodes == 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(uchar *str,struct jbList *list) { /* Add a node string to SEEN-BY list */ ulong c,d; uchar buf[60]; ushort 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,uchar *kludge) { struct Node4D node; uchar buf[60]; ulong 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,uchar *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,(ulong)strlen(buf)); } uchar *mmMakeSeenByBuf(struct jbList *list) { uchar *text; ulong seenbys,size; struct Nodes2D *nodes; ulong c; ushort lastnet; uchar 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: 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;cNodes;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); } crashmail-0.71/src/crashmail/memmessage.h0100644000000000000000000000317207762404650017146 0ustar rootroot#ifndef MEMMESSAGE_H #define MEMMESSAGE_H #define PKT_CHUNKLEN 10000 #define PKT_NUM2D 50 #define PKT_NUMPATH 10 struct TextChunk { struct TextChunk *Next; ulong Length; uchar Data[PKT_CHUNKLEN]; }; struct Nodes2D { struct Nodes2D *Next; ushort Nodes; ushort Net[PKT_NUM2D]; ushort Node[PKT_NUM2D]; }; struct Path { struct Path *Next; ushort Paths; uchar 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 { ulong msgnum; struct Node4D OrigNode; struct Node4D DestNode; struct Node4D PktOrig; struct Node4D PktDest; struct Node4D Origin4D; uchar Area[80]; uchar To[36]; uchar From[36]; uchar Subject[72]; uchar DateTime[20]; uchar MSGID[80]; uchar REPLY[80]; ushort Attr; ushort Cost; uchar Type; ushort Flags; struct jbList TextChunks; struct jbList SeenBy; struct jbList Path; }; bool mmAddNodes2DList(struct jbList *list,ushort net,ushort node); void mmRemNodes2DList(struct jbList *list,ushort net,ushort node); void mmRemNodes2DListPat(struct jbList *list,struct Node2DPat *pat); bool mmAddPath(uchar *str,struct jbList *list); bool mmAddBuf(struct jbList *chunklist,uchar *buf,ulong len); bool mmAddLine(struct MemMessage *mm,uchar *buf); struct MemMessage *mmAlloc(void); void mmClear(struct MemMessage *mm); void mmFree(struct MemMessage *mm); bool mmSortNodes2D(struct jbList *list); uchar *mmMakeSeenByBuf(struct jbList *list); #endif crashmail-0.71/src/crashmail/pkt.c0100644000000000000000000005725307764162465015634 0ustar rootroot#include "crashmail.h" /*************************************************************************/ /* */ /* Read Pkt */ /* */ /*************************************************************************/ #define PKT_MINREADLEN 200 bool messageend; bool shortread,longread; ushort getuword(uchar *buf,ulong offset) { return (ushort)(buf[offset]+256*buf[offset+1]); } void putuword(uchar *buf,ulong offset,ushort num) { buf[offset]=num%256; buf[offset+1]=num/256; } ulong ReadNull(uchar *buf, ulong 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); } ulong ReadCR(uchar *buf, ulong 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(uchar *pkt,struct osFileEntry *fe,bool bundled,bool (*handlefunc)(struct MemMessage *mm)) { osFile fh; struct Aka *tmpaka; struct ConfigNode *tmpcnode; ulong rlen,msgnum,msgoffset; uchar buf[200]; uchar PktHeader[SIZE_PKTHEADER]; uchar PktMsgHeader[SIZE_PKTMSGHEADER]; struct Node4D PktOrig,PktDest; uchar *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: %lu",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))) { ulong 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) { uchar domain[10]; mystrncpy(domain,&PktHeader[PKTHEADER45_ORIGDOMAIN],9); LogWrite(1,ACTIONINFO,"Tossing %s (%luK) from %ld:%ld/%ld.%ld@%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 (%luK) from %ld:%ld/%ld.%ld (%02ld-%s-%02ld %02ld:%02ld:%02ld) %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,&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 %ld) is too short",msgoffset); osClose(fh); mmFree(mm); sprintf(buf,"Message header for msg #1 (offset %ld) is too short",msgoffset); BadFile(pkt,buf); return(TRUE); } msgnum=0; while(getuword(PktMsgHeader,PKTMSGHEADER_PKTTYPE) == 2 && !ctrlc) { msgnum++; printf("Message %lu \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 #%lu (offset %ld) is short",msgnum,msgoffset); sprintf(buf,"Message header for msg #%lu (offset %ld) is short",msgnum,msgoffset); osClose(fh); mmFree(mm); BadFile(pkt,buf); return(TRUE); } if(longread) { LogWrite(1,TOSSINGERR,"Header strings too long in msg #%lu (offset %ld)",msgnum,msgoffset); sprintf(buf,"Header strings too long in msg #%lu (offset %ld)",msgnum,msgoffset); osClose(fh); mmFree(mm); BadFile(pkt,buf); return(TRUE); } /* Start reading message text */ messageend=FALSE; rlen=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) { rlen=ReadCR(buf,200,fh); if(shortread) { osClose(fh); mmFree(mm); LogWrite(1,TOSSINGERR,"Got unexpected EOF when reading msg #%lu (offset %ld)",msgnum,msgoffset); sprintf(buf,"Got unexpected EOF when reading msg #%lu (offset %ld)",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) { ulong 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 #%lu (offset %ld)",msgnum+1,msgoffset); osClose(fh); mmFree(mm); sprintf(buf,"Packet header too short for msg #%lu (offset %ld)",msgnum+1,msgoffset); BadFile(pkt,buf); return(TRUE); } } if(getuword(PktMsgHeader,PKTMSGHEADER_PKTTYPE)!=0) { osClose(fh); mmFree(mm); LogWrite(1,TOSSINGERR,"Unknown message type %lu for message #%lu (offset %ld)",getuword(PktMsgHeader,PKTMSGHEADER_PKTTYPE),msgnum+1,msgoffset); sprintf(buf,"Unknown message type %u for message #%lu (offset %ld)",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; ulong hexnum; ulong Len; ushort Type; struct Node4D Dest; struct Node4D Orig; }; void pktWrite(struct Pkt *pkt,uchar *buf,ulong len) { if(!osWrite(pkt->fh,buf,len)) { ioerror=TRUE; ioerrornum=osError(); } pkt->Len+=len; } void WriteNull(struct Pkt *pkt,uchar *str) { pktWrite(pkt,str,(ulong)(strlen(str)+1)); } struct Pkt *FindPkt(struct Node4D *node,struct Node4D *mynode,ushort 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; ulong serial; struct Pkt *CreatePkt(struct Node4D *dest,struct ConfigNode *node,struct Node4D *orig,ushort type) { uchar buf[100],buf2[100]; struct Pkt *pkt; ulong num,c; time_t t; struct tm *tp; uchar 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,"%08lx.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))) { ulong 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(&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,"",1); pktWrite(pkt,"",1); osClose(pkt->fh); if(pkt->hexnum) { uchar 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,"%08lx.newpkt",pkt->hexnum); sprintf(buf2,"%08lx_%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)) { ulong 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) { uchar 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) { ushort c; struct Path *path; for(path=(struct Path *)list->First;path;path=path->Next) for(c=0;cPaths;c++) if(path->Path[c][0]!=0) { pktWrite(pkt,"\x01PATH: ",7); pktWrite(pkt,path->Path[c],(ulong)strlen(path->Path[c])); pktWrite(pkt,"\x0d",1); } if(ioerror) return(FALSE); return(TRUE); } bool WriteSeenBy(struct Pkt *pkt,struct jbList *list) { uchar *buf; if(!(buf=mmMakeSeenByBuf(list))) return(FALSE); pktWrite(pkt,buf,(ulong)strlen(buf)); osFree(buf); return(TRUE); } bool WriteEchoMail(struct MemMessage *mm,struct ConfigNode *node, struct Aka *aka) { uchar buf[100]; struct Node4D *From4D; struct Pkt *pkt; struct TextChunk *chunk; ulong 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,buf,(ulong)strlen(buf)); if(ioerror) return(FALSE); for(chunk=(struct TextChunk *)mm->TextChunks.First;chunk;chunk=chunk->Next) { pktWrite(pkt,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,"",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; ulong 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,chunk->Data,chunk->Length); if(ioerror) return(FALSE); } pktWrite(pkt,"",1); return(TRUE); } crashmail-0.71/src/crashmail/pkt.h0100644000000000000000000000044607300264670015614 0ustar rootrootbool ReadPkt(uchar *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); crashmail-0.71/src/crashmail/mb_jam.c0100644000000000000000000007717510073762027016253 0ustar rootroot#include #define NO_TYPEDEF_UCHAR #define NO_TYPEDEF_USHORT #define NO_TYPEDEF_ULONG #include "crashmail.h" #define MIN(a,b) ((a)<(b)? (a):(b)) struct openbase { ulong lastuse; s_JamBase* Base_PS; struct jam_Area *area; }; struct jam_Area { struct jam_Area *Next; struct Area *area; s_JamBase *Base_PS; ulong BaseNum; ulong OldNum; ulong OldHighWater; ulong HighWater; bool newmsg; }; struct jbList jam_AreaList; struct openbase *jam_openbases; ulong jam_lastnum; long jam_utcoffset; int jam_linkmb(struct Area *area,ulong oldnum); s_JamBase *jam_openbase(struct jam_Area *area) { int c; struct openbase *thisbase; /* See if that area already is open */ for(c=0;clastuse) thisbase=&jam_openbases[c]; thisbase->lastuse=0; JAM_CloseMB(thisbase->Base_PS); free(thisbase->Base_PS); } /* Open area */ if(JAM_OpenMB(area->area->Path,&thisbase->Base_PS)) { if(thisbase->Base_PS) free(thisbase->Base_PS); LogWrite(2,SYSTEMINFO,"Creating JAM messagebase \"%s\"",area->area->Path); if(JAM_CreateMB(area->area->Path,1,&thisbase->Base_PS)) { if(thisbase->Base_PS) free(thisbase->Base_PS); LogWrite(1,SYSTEMERR,"Failed to create JAM messagebase \"%s\"",area->area->Path); return(NULL); } } /* Set the rest */ thisbase->lastuse=jam_lastnum++; thisbase->area=area; return(thisbase->Base_PS); } struct jam_Area *jam_getarea(struct Area *area) { struct jam_Area *ja; ulong num; s_JamBaseHeader Header_S; /* Check if area already exists */ for(ja=(struct jam_Area *)jam_AreaList.First;ja;ja=ja->Next) if(ja->area == area) { if(!(ja->Base_PS=jam_openbase(ja))) return(NULL); return(ja); } /* This is the first time we use this area */ if(!(ja=osAllocCleared(sizeof(struct jam_Area)))) { nomem=TRUE; return(FALSE); } jbAddNode(&jam_AreaList,(struct jbNode *)ja); ja->area=area; if(!(ja->Base_PS=jam_openbase(ja))) return(NULL); if(JAM_GetMBSize(ja->Base_PS,&num)) { LogWrite(1,TOSSINGERR,"Failed to get size of JAM area \"%s\"",area->Path); return(NULL); } ja->OldNum=num; if(JAM_ReadMBHeader(ja->Base_PS,&Header_S)) { LogWrite(1,TOSSINGERR,"Failed to read header of JAM area \"%s\"",area->Path); return(NULL); } ja->BaseNum=Header_S.BaseMsgNum; ja->OldHighWater=0; ja->HighWater=0; return(ja); } void jam_gethighwater(struct jam_Area *ja) { uchar buf[200]; osFile fh; ulong num; strcpy(buf,ja->area->Path); strcat(buf,".cmhw"); if((fh=osOpen(buf,MODE_OLDFILE))) { if(osRead(fh,&num,sizeof(ulong))) { ja->HighWater=num; ja->OldHighWater=num; } osClose(fh); } } void jam_writehighwater(struct jam_Area *ja) { uchar buf[200]; osFile fh; ulong num; strcpy(buf,ja->area->Path); strcat(buf,".cmhw"); num=ja->HighWater; if((fh=osOpen(buf,MODE_NEWFILE))) { osWrite(fh,&num,sizeof(ulong)); osClose(fh); } } bool jam_beforefunc(void) { time_t t1,t2; struct tm *tp; jbNewList(&jam_AreaList); if(config.cfg_jam_MaxOpen == 0) config.cfg_jam_MaxOpen = 5; if(!(jam_openbases=osAllocCleared(config.cfg_jam_MaxOpen * sizeof(struct openbase)))) { nomem=TRUE; return(FALSE); } /* Some timezone tricks */ t1=time(NULL); tp=gmtime(&t1); tp->tm_isdst=-1; t2=mktime(tp); jam_utcoffset=t2-t1; jam_lastnum=1; return(TRUE); } bool jam_afterfunc(bool success) { int c; struct jam_Area *ja; if(success && (config.cfg_jam_Flags & CFG_JAM_HIGHWATER)) for(ja=(struct jam_Area *)jam_AreaList.First;ja;ja=ja->Next) if(ja->HighWater != ja->OldHighWater) jam_writehighwater(ja); if(success && (config.cfg_jam_Flags & CFG_JAM_LINK)) for(ja=(struct jam_Area *)jam_AreaList.First;ja;ja=ja->Next) if(ja->newmsg) jam_linkmb(ja->area,ja->OldNum); for(c=0;cnewmsg=TRUE; JAM_ClearMsgHeader(&Header_S); if(!(SubPacket_PS = JAM_NewSubPacket())) { nomem=TRUE; return(FALSE); } /* Allocate memory to store message text in */ msgpos=0; msgsize=0; 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"); JAM_DelSubPacket(SubPacket_PS); return(FALSE); } } /* Do header */ Header_S.DateProcessed = time(NULL); Header_S.DateWritten = FidoToTime(mm->DateTime); /* Damned time zones... dates should be in local time in JAM */ Header_S.DateProcessed -= jam_utcoffset; Header_S.DateWritten -= jam_utcoffset; Header_S.Cost=mm->Cost; Header_S.MsgIdCRC=JAM_Crc32(mm->MSGID,strlen(mm->MSGID)); Header_S.ReplyCRC=JAM_Crc32(mm->REPLY,strlen(mm->REPLY)); /* Add header fields */ if(mm->From[0]) jam_addfield(SubPacket_PS,JAMSFLD_SENDERNAME,mm->From); if(mm->To[0]) jam_addfield(SubPacket_PS,JAMSFLD_RECVRNAME,mm->To); if(mm->Subject[0]) jam_addfield(SubPacket_PS,JAMSFLD_SUBJECT,mm->Subject); if(mm->Area[0] == 0) { /* Addresses in netmail */ Print4D(&mm->OrigNode,buf); jam_addfield(SubPacket_PS,JAMSFLD_OADDRESS,buf); Print4D(&mm->DestNode,buf); jam_addfield(SubPacket_PS,JAMSFLD_DADDRESS,buf); } else { /* Addresses in echomail */ Print4D(&mm->Origin4D,buf); jam_addfield(SubPacket_PS,JAMSFLD_OADDRESS,buf); } /* Header attributes */ for(c=0;jam_flagarray[c].name;c++) if(mm->Attr & jam_flagarray[c].fidoflagbit) Header_S.Attribute |= jam_flagarray[c].jamflagbit; if(mm->Attr & FLAG_FILEATTACH) { Header_S.Attribute |= MSG_FILEATTACH; c=0; while(mm->Subject[c]!=0) { f=0; while(mm->Subject[c]!=0 && mm->Subject[c]!=32 && mm->Subject[c]!=',' && f<80) buf[f++]=mm->Subject[c++]; buf[f]=0; while(mm->Subject[c]==32 || mm->Subject[c]==',') c++; if(buf[0]!=0) jam_addfield(SubPacket_PS,JAMSFLD_ENCLFILE,buf); } } if(mm->Attr & FLAG_FILEREQ) { Header_S.Attribute |= MSG_FILEREQUEST; c=0; while(mm->Subject[c]!=0) { f=0; while(mm->Subject[c]!=0 && mm->Subject[c]!=32 && mm->Subject[c]!=',' && f<80) buf[f++]=mm->Subject[c++]; buf[f]=0; while(mm->Subject[c]==32 || mm->Subject[c]==',') c++; if(buf[0]!=0) jam_addfield(SubPacket_PS,JAMSFLD_ENCLFREQ,buf); } } /* Echomail/netmail attribute */ if(mm->Area[0]==0) Header_S.Attribute |= MSG_TYPENET; else Header_S.Attribute |= MSG_TYPEECHO; /* Separate kludges from text */ for(chunk=(struct TextChunk *)mm->TextChunks.First;chunk;chunk=chunk->Next) for(c=0;cLength;) { linebegin=msgpos; while(chunk->Data[c]!=13 && cLength) { if(chunk->Data[c]!=10) msgtext[msgpos++]=chunk->Data[c]; c++; } if(chunk->Data[c]==13 && cLength) msgtext[msgpos++]=chunk->Data[c++]; linelen=msgpos-linebegin; if(linelen!=0) { if(linelen>=5 && strncmp(&msgtext[linebegin],"\x01""PID:",5)==0) { mystrncpy(buf,&msgtext[linebegin+5],MIN(100,linelen-5)); stripleadtrail(buf); jam_addfield(SubPacket_PS,JAMSFLD_PID,buf); msgpos=linebegin; } else if(linelen>=7 && strncmp(&msgtext[linebegin],"\x01""MSGID:",7)==0) { mystrncpy(buf,&msgtext[linebegin+7],MIN(100,linelen-7)); stripleadtrail(buf); jam_addfield(SubPacket_PS,JAMSFLD_MSGID,buf); msgpos=linebegin; } else if(linelen>=7 && strncmp(&msgtext[linebegin],"\x01""REPLY:",7)==0) { mystrncpy(buf,&msgtext[linebegin+7],MIN(100,linelen-7)); stripleadtrail(buf); jam_addfield(SubPacket_PS,JAMSFLD_REPLYID,buf); msgpos=linebegin; } else if(linelen>=7 && strncmp(&msgtext[linebegin],"\x01""FLAGS:",7)==0) { mystrncpy(buf,&msgtext[linebegin+7],MIN(100,linelen-7)); stripleadtrail(buf); jbcpos=0; newflags[0]=0; while(jbstrcpy(flag,buf,10,&jbcpos)) { ulong flagbit; if((flagbit=jam_findflag(flag))) { Header_S.Attribute |= flagbit; } else { strcat(newflags,flag); strcat(newflags," "); } } stripleadtrail(newflags); if(newflags[0]!=0) jam_addfield(SubPacket_PS,JAMSFLD_FLAGS,newflags); 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) { mystrncpy(buf,&msgtext[linebegin+1],MIN(100,linelen-1)); stripleadtrail(buf); jam_addfield(SubPacket_PS,JAMSFLD_FTSKLUDGE,buf); msgpos=linebegin; } } } /* Seen-by */ if(config.cfg_Flags & CFG_IMPORTSEENBY) { uchar *buf; ulong c,d; if((buf=mmMakeSeenByBuf(&mm->SeenBy))) { c=0; while(buf[c]!=0) { d=c; while(buf[d]!=0 && buf[d]!=13) d++; if(buf[d]==13) { buf[d++]=0; jam_addfield(SubPacket_PS,JAMSFLD_SEENBY2D,&buf[c+9]); } c=d; } } osFree(buf); } /* Path */ for(pathnode=(struct Path *)mm->Path.First;pathnode;pathnode=pathnode->Next) for(c=0;cPaths;c++) jam_addfield(SubPacket_PS,JAMSFLD_PATH2D,pathnode->Path[c]); if(jam_nomem) { LogWrite(1,SYSTEMERR,"Out of memory"); JAM_DelSubPacket(SubPacket_PS); if(msgsize) osFree(msgtext); return(FALSE); } /* Write message */ if(JAM_LockMB(ja->Base_PS,10)) { LogWrite(1,SYSTEMERR,"Timeout when trying to lock JAM messagebase \"%s\"",area->Path); JAM_DelSubPacket(SubPacket_PS); if(msgsize) osFree(msgtext); return(FALSE); } if(msgsize == 0) { msgtext=""; msgpos=1; } res=JAM_AddMessage(ja->Base_PS,&Header_S,SubPacket_PS,msgtext,msgpos); JAM_UnlockMB(ja->Base_PS); JAM_DelSubPacket(SubPacket_PS); if(msgsize) osFree(msgtext); if(res) { LogWrite(1,SYSTEMERR,"Failed to write message to JAM messagebase \"%s\"",area->Path); return(FALSE); } return(TRUE); } void jam_makekludge(struct MemMessage *mm,uchar *pre,uchar *data,ulong len) { uchar *buf; 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 jam_ExportJAMNum(struct Area *area,ulong num,bool (*handlefunc)(struct MemMessage *mm),bool isrescanning) { struct MemMessage *mm; struct jam_Area *ja; uchar *msgtext; uchar buf[200],domain[20]; int res,c; s_JamSubPacket* SubPacket_PS; s_JamMsgHeader Header_S; s_JamSubfield* Field_PS; struct Node4D n4d; bool hasaddr; uchar flagsbuf[200],filesubject[200]; ushort oldattr; /* Open the area */ if(!(ja=jam_getarea(area))) return(FALSE); /* Read message header */ res=JAM_ReadMsgHeader(ja->Base_PS,num-ja->BaseNum,&Header_S,&SubPacket_PS); if(res) { if(res == JAM_NO_MESSAGE) { return(TRUE); /* Message no longer exists */ } else { LogWrite(1,TOSSINGERR,"Failed to read message #%lu in JAM messagebase \"%s\"",num,area->Path); return(TRUE); } } /* Check if deleted */ if(Header_S.Attribute & MSG_DELETED) { /* Message deleted */ JAM_DelSubPacket(SubPacket_PS); return(TRUE); } /* Check if already sent */ if(!isrescanning) { if((Header_S.Attribute & MSG_SENT) || !(Header_S.Attribute & MSG_LOCAL)) { /* Don't touch if the message is sent or not local */ JAM_DelSubPacket(SubPacket_PS); return(TRUE); } } /* Read message text */ msgtext=NULL; if(Header_S.TxtLen) { if(!(msgtext=osAlloc(Header_S.TxtLen+1))) /* One extra byte for the terminating zero */ { nomem=TRUE; JAM_DelSubPacket(SubPacket_PS); return(FALSE); } res=JAM_ReadMsgText(ja->Base_PS,Header_S.TxtOffset,Header_S.TxtLen,msgtext); if(res) { LogWrite(1,TOSSINGERR,"Failed to read message #%lu in JAM messagebase \"%s\"",num,area->Path); JAM_DelSubPacket(SubPacket_PS); return(FALSE); } msgtext[Header_S.TxtLen]=0; } /* Allocate message structure */ if(!(mm=mmAlloc())) { JAM_DelSubPacket(SubPacket_PS); if(msgtext) osFree(msgtext); return(FALSE); } if(area->AreaType == AREATYPE_NETMAIL) strcpy(mm->Area,""); else strcpy(mm->Area,area->Tagname); mm->msgnum=num; /* Subfields */ flagsbuf[0]=0; filesubject[0]=0; hasaddr=FALSE; for(Field_PS=JAM_GetSubfield(SubPacket_PS);Field_PS;Field_PS=JAM_GetSubfield(NULL)) { switch(Field_PS->LoID) { case JAMSFLD_OADDRESS: mystrncpy(buf,Field_PS->Buffer,Field_PS->DatLen+1); if(Parse5D(buf,&n4d,domain)) { mm->OrigNode.Zone=n4d.Zone; mm->OrigNode.Net=n4d.Net; mm->OrigNode.Node=n4d.Node; mm->OrigNode.Point=n4d.Point; } break; case JAMSFLD_DADDRESS: mystrncpy(buf,Field_PS->Buffer,Field_PS->DatLen+1); if(hasaddr) { LogWrite(1,TOSSINGERR,"Warning: Multiple DADDRESS not supported by CrashMail"); } else { hasaddr=TRUE; if(Parse5D(buf,&n4d,domain)) { mm->DestNode.Zone=n4d.Zone; mm->DestNode.Net=n4d.Net; mm->DestNode.Node=n4d.Node; mm->DestNode.Point=n4d.Point; } } break; case JAMSFLD_SENDERNAME: mystrncpy(buf,Field_PS->Buffer,Field_PS->DatLen+1); mystrncpy(mm->From,buf,36); break; case JAMSFLD_RECVRNAME: mystrncpy(buf,Field_PS->Buffer,Field_PS->DatLen+1); mystrncpy(mm->To,buf,36); break; case JAMSFLD_MSGID: jam_makekludge(mm,"\x01" "MSGID: ",Field_PS->Buffer,Field_PS->DatLen); break; case JAMSFLD_REPLYID: jam_makekludge(mm,"\x01" "REPLY: ",Field_PS->Buffer,Field_PS->DatLen); break; case JAMSFLD_SUBJECT: mystrncpy(buf,Field_PS->Buffer,Field_PS->DatLen+1); mystrncpy(mm->Subject,buf,72); break; case JAMSFLD_PID: jam_makekludge(mm,"\x01" "PID: ",Field_PS->Buffer,Field_PS->DatLen); break; case JAMSFLD_ENCLFILE: if(filesubject[0]) LogWrite(1,TOSSINGERR,"Warning: Multiple ENCLOSEDFILE not supported by CrashMail"); else mystrncpy(filesubject,Field_PS->Buffer,Field_PS->DatLen+1); break; case JAMSFLD_ENCLFREQ: LogWrite(1,TOSSINGERR,"Warning: ENCLOSEDFREQ not supported by CrashMail"); break; case JAMSFLD_ENCLFWALIAS: LogWrite(1,TOSSINGERR,"Warning: ENCLOSEDFILEWALIAS not supported by CrashMail"); break; case JAMSFLD_ENCLFILEWC: LogWrite(1,TOSSINGERR,"Warning: ENCLOSEDFILEWCARD with wildcards not supported by CrashMail"); break; case JAMSFLD_ENCLINDFILE: LogWrite(1,TOSSINGERR,"Warning: ENCLOSEDINDIRECTFILE not supported by CrashMail"); break; case JAMSFLD_FTSKLUDGE: jam_makekludge(mm,"\x01",Field_PS->Buffer,Field_PS->DatLen); break; case JAMSFLD_SEENBY2D: jam_makekludge(mm,"SEEN-BY: ",Field_PS->Buffer,Field_PS->DatLen); break; case JAMSFLD_PATH2D: jam_makekludge(mm,"\01" "PATH: ",Field_PS->Buffer,Field_PS->DatLen); break; case JAMSFLD_FLAGS: strcpy(flagsbuf,"\x01" "FLAGS: "); mystrncpy(&flagsbuf[8],Field_PS->Buffer,Field_PS->DatLen+1); /* Don't add until attributes from header has been added */ break; } } if(filesubject[0]) { mm->Attr|=FLAG_FILEATTACH; mystrncpy(mm->Subject,filesubject,72); } /* Message header */ MakeFidoDate(Header_S.DateWritten+jam_utcoffset,mm->DateTime); mm->Cost=Header_S.Cost; for(c=0;jam_flagarray[c].name;c++) if(Header_S.Attribute & jam_flagarray[c].jamflagbit) { if(jam_flagarray[c].fidoflagbit) { mm->Attr |= jam_flagarray[c].fidoflagbit; } else if(jam_flagarray[c].name[0] && strlen(flagsbuf)<90) { if(flagsbuf[0]==0) strcpy(flagsbuf,"\x01" "FLAGS: "); else strcat(flagsbuf," "); strcat(flagsbuf,jam_flagarray[c].name); } } if(flagsbuf[0]) { strcat(flagsbuf,"\x0d"); mmAddLine(mm,buf); } oldattr = mm->Attr; mm->Attr = mm->Attr & (FLAG_PVT|FLAG_CRASH|FLAG_FILEATTACH|FLAG_FILEREQ|FLAG_RREQ|FLAG_IRRR|FLAG_AUDIT|FLAG_HOLD); /* Add own kludges */ if(area->AreaType == AREATYPE_NETMAIL) { if(mm->OrigNode.Zone != mm->DestNode.Zone || (config.cfg_Flags & CFG_FORCEINTL)) { sprintf(buf,"\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,buf); } if(mm->OrigNode.Point) { sprintf(buf,"\x01" "FMPT %u\x0d",mm->OrigNode.Point); mmAddLine(mm,buf); } if(mm->DestNode.Point) { sprintf(buf,"\x01" "TOPT %u\x0d",mm->DestNode.Point); mmAddLine(mm,buf); } } if((config.cfg_Flags & CFG_ADDTID) && !isrescanning) AddTID(mm); if(isrescanning) { sprintf(buf,"\x01RESCANNED %u:%u/%u.%u\x0d",area->Aka->Node.Zone, area->Aka->Node.Net, area->Aka->Node.Node, area->Aka->Node.Point); mmAddLine(mm,buf); } /* Message text */ if(msgtext) { /* Extract origin address */ if(mm->Area[0]) { ulong textpos,d; uchar 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,Header_S.TxtLen))) { JAM_DelSubPacket(SubPacket_PS); osFree(msgtext); mmFree(mm); return(FALSE); } } /* Free JAM message */ if(msgtext) osFree(msgtext); JAM_DelSubPacket(SubPacket_PS); /* Message reading done */ if(isrescanning) mm->Flags |= MMFLAG_RESCANNED; else mm->Flags |= MMFLAG_EXPORTED; if(!(*handlefunc)(mm)) { mmFree(mm); return(FALSE); } if(!isrescanning) { scan_total++; /* Update message header */ if(config.cfg_Flags & CFG_ALLOWKILLSENT) { if((oldattr & FLAG_KILLSENT) && (area->AreaType == AREATYPE_NETMAIL)) { /* Delete message with KILLSENT flag */ LogWrite(2,TOSSINGINFO,"Deleting message with KILLSENT flag"); Header_S.Attribute |= MSG_DELETED; } } Header_S.Attribute |= MSG_SENT; Header_S.DateProcessed = time(NULL); Header_S.DateProcessed -= jam_utcoffset; /* jam_openbases might have been changed in handlefunc */ if(!(ja=jam_getarea(area))) { mmFree(mm); return(FALSE); } if(JAM_LockMB(ja->Base_PS,10)) { LogWrite(1,SYSTEMERR,"Timeout when trying to lock JAM messagebase \"%s\"",area->Path); mmFree(mm); return(FALSE); } if(JAM_ChangeMsgHeader(ja->Base_PS,num-ja->BaseNum,&Header_S)) LogWrite(1,TOSSINGERR,"Failed to update header of message #%lu in JAM messagebase \"%s\"",num,area->Path); JAM_UnlockMB(ja->Base_PS); } mmFree(mm); return(TRUE); } bool jam_exportfunc(struct Area *area,bool (*handlefunc)(struct MemMessage *mm)) { ulong start,end; struct jam_Area *ja; /* Open the area */ if(!(ja=jam_getarea(area))) { if(nomem) return(FALSE); return(TRUE); /* Area did not exist and could not be created. Go on anyway. */ } if(config.cfg_jam_Flags & CFG_JAM_HIGHWATER) jam_gethighwater(ja); if(ja->HighWater) start=ja->HighWater+1; else start=ja->BaseNum; if(start < ja->BaseNum) start=ja->BaseNum; end = ja->BaseNum + ja->OldNum; while(start < end && !ctrlc) { if(!jam_ExportJAMNum(area,start,handlefunc,FALSE)) return(FALSE); start++; } if(ctrlc) return(FALSE); ja->HighWater=end-1; return(TRUE); } bool jam_rescanfunc(struct Area *area,ulong max,bool (*handlefunc)(struct MemMessage *mm)) { ulong start; struct jam_Area *ja; /* Open the area */ if(!(ja=jam_getarea(area))) return(FALSE); start=ja->BaseNum; if(max !=0 && ja->OldNum > max) start=ja->BaseNum+ja->OldNum-max; while(start < ja->BaseNum + ja->OldNum && !ctrlc) { if(!jam_ExportJAMNum(area,start,handlefunc,TRUE)) return(FALSE); start++; } if(ctrlc) return(FALSE); return(TRUE); } /************************** Linking ***********************/ struct Msg { unsigned long MsgIdCRC; unsigned long ReplyCRC; unsigned long ReplyTo; unsigned long Reply1st; unsigned long ReplyNext; unsigned long OldReplyTo; unsigned long OldReply1st; unsigned long OldReplyNext; }; int jam_CompareMsgIdReply(s_JamBase *Base_PS,struct Msg *msgs,ulong msgidmsg,ulong replymsg) { int Status_I; s_JamMsgHeader MsgIdHeader_S; s_JamMsgHeader ReplyHeader_S; s_JamSubPacket* MsgIdSubPacket_PS; s_JamSubPacket* ReplySubPacket_PS; s_JamSubfield* MsgIdField_PS = NULL; s_JamSubfield* ReplyField_PS = NULL; if(msgs[msgidmsg].MsgIdCRC != msgs[replymsg].ReplyCRC) return(FALSE); if(config.cfg_jam_Flags & CFG_JAM_QUICKLINK) return(TRUE); Status_I = JAM_ReadMsgHeader(Base_PS,msgidmsg,&MsgIdHeader_S,&MsgIdSubPacket_PS ); if(Status_I) return(FALSE); Status_I = JAM_ReadMsgHeader(Base_PS,replymsg,&ReplyHeader_S,&ReplySubPacket_PS ); if(Status_I) { JAM_DelSubPacket(MsgIdSubPacket_PS); return(FALSE); } for ( MsgIdField_PS = JAM_GetSubfield( MsgIdSubPacket_PS ); MsgIdField_PS; MsgIdField_PS = JAM_GetSubfield( NULL ) ) if(MsgIdField_PS->LoID == JAMSFLD_MSGID) break; for ( ReplyField_PS = JAM_GetSubfield( ReplySubPacket_PS ); ReplyField_PS; ReplyField_PS = JAM_GetSubfield( NULL ) ) if(ReplyField_PS->LoID == JAMSFLD_REPLYID) break; if(!ReplyField_PS || !MsgIdField_PS) { JAM_DelSubPacket(MsgIdSubPacket_PS); JAM_DelSubPacket(ReplySubPacket_PS); return(FALSE); } if(ReplyField_PS->DatLen != MsgIdField_PS->DatLen) { JAM_DelSubPacket(MsgIdSubPacket_PS); JAM_DelSubPacket(ReplySubPacket_PS); return(FALSE); } if(strncmp(ReplyField_PS->Buffer,MsgIdField_PS->Buffer,ReplyField_PS->DatLen) != 0) { JAM_DelSubPacket(MsgIdSubPacket_PS); JAM_DelSubPacket(ReplySubPacket_PS); return(FALSE); } JAM_DelSubPacket(MsgIdSubPacket_PS); JAM_DelSubPacket(ReplySubPacket_PS); return(TRUE); } /* dest is a reply to num */ void jam_setreply(struct Msg *msgs,ulong nummsgs,ulong base,ulong num,ulong dest) { int n,times; if(msgs[dest].ReplyTo) return; /* Already linked */ msgs[dest].ReplyTo=num+base; if(msgs[num].Reply1st == 0) { msgs[num].Reply1st=dest+base; } else { n=msgs[num].Reply1st-base; if(n == dest) return; if (n < 0 || n >= nummsgs) { /* Oops! Base seems to be b0rken */ printf("Warning: message #%ld is linked to something outside the base\n", num + base); return; } times=0; while(msgs[n].ReplyNext) { times++; if(times > 1000) /* Something appears to have gone wrong */ { printf("Warning: >1000 replies to message %ld or circular reply links\n",num+base); return; } n=msgs[n].ReplyNext-base; if(n == dest) return; if (n < 0 || n >= nummsgs) { /* Oops! Base seems to be b0rken */ printf("Warning: message #%ld is linked to something outside the base\n", num + base); return; } } msgs[n].ReplyNext=dest+base; } } int jam_linkmb(struct Area *area,ulong oldnum) { struct jam_Area *ja; ulong nummsgs,res,c,d; struct Msg *msgs; printf("Linking JAM area %s \n",area->Tagname); fflush(stdout); if(!(ja=jam_getarea(area))) return(FALSE); if(JAM_GetMBSize(ja->Base_PS,&nummsgs)) { LogWrite(1,TOSSINGERR,"Failed to get size of JAM area \"%s\"",area->Path); return(FALSE); } if(nummsgs == 0) return(TRUE); /* Nothing to do */ /* Read msgid/reply */ if(!(msgs=osAlloc(nummsgs*sizeof(struct Msg)))) { LogWrite(1,SYSTEMERR,"Out of memory, cannot link JAM area %s",area->Tagname); return(FALSE); } for(c=0;cBase_PS, c, &Header_S, NULL); msgs[c].MsgIdCRC=-1; msgs[c].ReplyCRC=-1; msgs[c].ReplyTo=0; msgs[c].Reply1st=0; msgs[c].ReplyNext=0; msgs[c].OldReplyTo=0; msgs[c].OldReply1st=0; msgs[c].OldReplyNext=0; if(!res) { msgs[c].MsgIdCRC=Header_S.MsgIdCRC; msgs[c].ReplyCRC=Header_S.ReplyCRC; msgs[c].ReplyTo=Header_S.ReplyTo; msgs[c].Reply1st=Header_S.Reply1st; msgs[c].ReplyNext=Header_S.ReplyNext; msgs[c].OldReplyTo=Header_S.ReplyTo; msgs[c].OldReply1st=Header_S.Reply1st; msgs[c].OldReplyNext=Header_S.ReplyNext; } } for(c=oldnum;cBase_PS,msgs,d,c)) jam_setreply(msgs,nummsgs,ja->BaseNum,d,c); } if(msgs[c].MsgIdCRC != -1) { /* See if there are any replies to this message */ for(d=0;dBase_PS,msgs,c,d)) jam_setreply(msgs,nummsgs,ja->BaseNum,c,d); } } /* Update links */ for(c=0;cBase_PS,10)) { LogWrite(1,SYSTEMERR,"Timeout when trying to lock JAM messagebase \"%s\"",area->Path); osFree(msgs); return(FALSE); } res = JAM_ReadMsgHeader( ja->Base_PS, c, &Header_S, NULL); if(!res) { Header_S.ReplyTo=msgs[c].ReplyTo; Header_S.Reply1st=msgs[c].Reply1st; Header_S.ReplyNext=msgs[c].ReplyNext; JAM_ChangeMsgHeader(ja->Base_PS,c,&Header_S); JAM_UnlockMB(ja->Base_PS); } } osFree(msgs); return(TRUE); } crashmail-0.71/src/crashmail/mb_jam.h0100644000000000000000000000045107300264670016237 0ustar rootrootbool 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,ulong max,bool (*handlefunc)(struct MemMessage *mm)); crashmail-0.71/src/crashmail/mb_msg.c0100644000000000000000000003123207764163403016260 0ustar rootroot#include "crashmail.h" struct msg_Area { struct msg_Area *Next; struct Area *area; ulong LowMsg; ulong HighMsg; ulong OldHighWater; ulong HighWater; }; bool msg_GetHighLowMsg(struct msg_Area *area); bool msg_WriteHighWater(struct msg_Area *area); bool msg_WriteMSG(struct MemMessage *mm,uchar *file); ulong msg_ReadCR(uchar *buf, ulong maxlen, osFile fh); bool msg_ExportMSGNum(struct Area *area,ulong 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) { uchar buf[200],buf2[20]; struct msg_Area *ma; if(!(ma=msg_getarea(area))) return(FALSE); ma->HighMsg++; sprintf(buf2,"%lu.msg",ma->HighMsg); MakeFullPath(ma->area->Path,buf2,buf,200); while(osExists(buf)) { ma->HighMsg++; sprintf(buf2,"%lu.msg",ma->HighMsg); MakeFullPath(ma->area->Path,buf2,buf,200); } return msg_WriteMSG(mm,buf); } bool msg_rescanfunc(struct Area *area,ulong max,bool (*handlefunc)(struct MemMessage *mm)) { ulong 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)) { ulong start; uchar 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(startLowMsg) 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,ulong num,bool (*handlefunc)(struct MemMessage *mm),bool isrescanning) { ulong rlen; uchar buf[200],buf2[50]; bool kludgeadd; osFile fh; struct StoredMsg Msg; struct MemMessage *mm; ushort oldattr; struct msg_Area *ma; if(!(ma=msg_getarea(area))) return(FALSE); if(!(mm=mmAlloc())) return(FALSE); sprintf(buf2,"%lu.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 { rlen=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,"%lu.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); } ulong msg_templowmsg; ulong msg_temphighmsg; void msg_scandirfunc(uchar *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)) { ulong 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)) { ulong 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; uchar 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,"CrashMail II"); 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))) { ulong 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,uchar *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) { uchar *sbbuf; if(!(sbbuf=mmMakeSeenByBuf(&mm->SeenBy))) { osClose(fh); return(FALSE); } if(sbbuf[0]) { if(!osWrite(fh,sbbuf,(ulong)strlen(sbbuf))) { ioerror=TRUE; ioerrornum=osError(); } } osFree(sbbuf); } /* Write path */ for(path=(struct Path *)mm->Path.First;path;path=path->Next) for(c=0;cPaths;c++) if(path->Path[c][0]!=0) { if(!osWrite(fh,"\x01PATH: ",7)) { ioerror=TRUE; ioerrornum=osError(); } if(!osWrite(fh,path->Path[c],(ulong)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); } ulong msg_ReadCR(uchar *buf, ulong 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); } crashmail-0.71/src/crashmail/mb_msg.h0100644000000000000000000000045107300264670016256 0ustar rootrootbool 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,ulong max,bool (*handlefunc)(struct MemMessage *mm)); crashmail-0.71/src/crashmail/filter.c0100644000000000000000000005171607763455472016323 0ustar rootroot#include "crashmail.h" /* Boyer-Moore search routines */ ushort bmstep[256]; void bminit(uchar *pat) { int i,len; len=strlen(pat); for(i=0;i<256;i++) bmstep[i]=0; for(i=0;i=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(uchar *var,struct Node4D *node,uchar *operator,uchar *data,int opn,int datan,int *errpos,uchar **errstr) { static uchar 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(uchar *var,uchar *str,uchar *operator,uchar *data,int opn,int datan,int *errpos,uchar **errstr) { static uchar 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(uchar *var,bool bl,uchar *operator,uchar *data,int opn,int datan,int *errpos,uchar **errstr) { static uchar 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(uchar *var,struct MemMessage *mm,bool kludge,uchar *operator,uchar *data,int opn,int datan,int *errpos,uchar **errstr) { static uchar 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(uchar *str,int *errpos,uchar **errstr) { uchar type[20],source[20]; static uchar errbuf[100]; struct Aka *aka; struct ConfigNode *cnode; bool fileattach,tolocalaka,fromlocalaka,tolocalpoint,fromlocalpoint; bool existscfg_fromaddr,existscfg_fromboss,existscfg_toaddr,existscfg_toboss; uchar 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) { uchar 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) { uchar 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,uchar *tagname) { struct Area *area; struct TextChunk *tmp; struct jbList oldlist; uchar 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,uchar *reason) { LogWrite(4,TOSSINGINFO,"Filter: Writing message to BAD area (\"%s\")",reason); return WriteBad(mm,reason); } bool Filter_WriteLog(struct MemMessage *mm,uchar *cmd) { uchar buf[400]; uchar 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,uchar *cmd) { bool msg,rfc1,rfc2; uchar msgbuf[L_tmpnam],rfcbuf1[L_tmpnam],rfcbuf2[L_tmpnam]; uchar origbuf[30],destbuf[30]; uchar 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 %lu, exiting...",arcres); return(FALSE); } return(TRUE); } bool Filter_Bounce(struct MemMessage *mm,uchar *reason,bool headeronly) { uchar reasonbuf[400]; uchar 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,uchar *namepat,struct Node4DPat *destpat) { struct Route *tmproute; struct jbList oldlist; struct TextChunk *tmp; uchar buf[100]; uchar oldto[36],newto[36]; struct Node4D olddest4d,newdest4d,my4d; ulong 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 %lu:%lu/%lu.%lu", newto, newdest4d.Zone, newdest4d.Net, newdest4d.Node, newdest4d.Point); LogWrite(4,SYSTEMINFO,"Filter: Message originally to %s at %lu:%lu/%lu.%lu", 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(cLength) { for(d=c;dLength && 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; uchar *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(uchar *filter,uchar *cfgerr) { struct expr *expr; uchar *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;crectype != -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,(uchar *)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,(uchar *)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); } ulong v7p_unpack(uchar *dest,uchar *pack,ulong size) { ulong c,d; ushort w; uchar *table=" EANROSTILCHBDMUGPKYWFVJXZQ-'0123456789"; d=0; for(c=0;c 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(uchar *errbuf) { uchar 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(ushort))!=sizeof(ushort)) { 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 uchars, max is %d uchars)",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) { ulong junk; if(v7p_findoffset(node,&junk)) return(TRUE); return(FALSE); } long v7p_nlGetHub(struct Node4D *node) { struct Node4D t4d; ulong 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; ulong 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) { uchar 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: %ld\n",v7p_nlCheckNode(&n)); printf(" hub: %ld\n",v7p_nlGetHub(&n)); printf("region: %ld\n",v7p_nlGetRegion(&n)); v7p_nlEnd(); exit(0); } */ crashmail-0.71/src/crashmail/nl_v7p.h0100644000000000000000000000026507053232416016220 0ustar rootrootbool v7p_nlStart(uchar *errbuf); void v7p_nlEnd(void); bool v7p_nlCheckNode(struct Node4D *node); long v7p_nlGetHub(struct Node4D *node); long v7p_nlGetRegion(struct Node4D *node); crashmail-0.71/src/crashmail/handle.c0100644000000000000000000012763307763707210016261 0ustar rootroot#include "crashmail.h" bool HandleEchomail(struct MemMessage *mm); bool HandleNetmail(struct MemMessage *mm); bool HandleRescan(struct MemMessage *mm); bool HandleMessage(struct MemMessage *mm) { bool res; LogWrite(6,DEBUG,"Is in HandleMessage()"); handle_nesting++; if(mm->Area[0]==0) res=HandleNetmail(mm); else res=HandleEchomail(mm); handle_nesting--; return(res); } /**************************** auto-add *****************************/ bool GetDescription(uchar *area,struct ConfigNode *node,uchar *desc) { struct Arealist *arealist; uchar buf[200]; ulong c,d; osFile fh; for(arealist=(struct Arealist *)config.ArealistList.First;arealist;arealist=arealist->Next) { if(arealist->Node == node && (arealist->Flags & AREALIST_DESC)) { if((fh=osOpen(arealist->AreaFile,MODE_OLDFILE))) { while(osFGets(fh,buf,199)) { for(c=0;buf[c]>32;c++); if(buf[c]!=0) { buf[c]=0; if(stricmp(buf,area)==0) { c++; while(buf[c]<=32 && buf[c]!=0) c++; if(buf[c]!=0) { d=0; while(buf[c]!=0 && buf[c]!=10 && buf[c]!=13 && d<77) desc[d++]=buf[c++]; desc[d]=0; osClose(fh); return(TRUE); } } } } osClose(fh); } else { ulong err=osError(); LogWrite(1,SYSTEMERR,"Failed to open file \"%s\"\n",arealist->AreaFile); LogWrite(1,SYSTEMERR,"Error: %s",osErrorMsg(err)); } } } return(FALSE); } bool AddTossNode(struct Area *area,struct ConfigNode *cnode,ushort flags) { struct TossNode *tnode; /* Check if it already exists */ for(tnode=(struct TossNode *)area->TossNodes.First;tnode;tnode=tnode->Next) if(tnode->ConfigNode == cnode) return(TRUE); if(!(tnode=(struct TossNode *)osAllocCleared(sizeof(struct TossNode)))) { nomem=TRUE; return(FALSE); } jbAddNode((struct jbList *)&area->TossNodes,(struct jbNode *)tnode), tnode->ConfigNode=cnode; tnode->Flags=flags; return(TRUE); } time_t lastt; void MakeDirectory(uchar *dest,ulong destsize,uchar *defdir,uchar *areaname) { ulong c,d; uchar lowercase[200],shortname[50]; /* Convert to lower case */ strcpy(lowercase,areaname); for(c=0;lowercase[c]!=0;c++) lowercase[c]=tolower(lowercase[c]); /* Make 8 digit serial number */ if(lastt == 0) lastt=time(NULL); else lastt++; sprintf(shortname,"%08lx",lastt); d=0; for(c=0;cTossNodes); jbNewList(&temparea->BannedNodes); jbAddNode(&config.AreaList,(struct jbNode *)temparea); for(tempaka=(struct Aka *)config.AkaList.First;tempaka;tempaka=tempaka->Next) if(Compare4D(&tempaka->Node,mynode)==0) break; if(!tempaka) tempaka=(struct Aka *)config.AkaList.First; for(tempcnode=(struct ConfigNode *)config.CNodeList.First;tempcnode;tempcnode=tempcnode->Next) if(Compare4D(&tempcnode->Node,node)==0) break; /* Find default area to use */ defarea=NULL; /* First we try to find one for specific groups */ if(tempcnode && tempcnode->DefaultGroup) { uchar groups[100]; for(defarea=(struct Area *)config.AreaList.First;defarea;defarea=defarea->Next) if(strnicmp(defarea->Tagname,"DEFAULT_",8)==0) { mystrncpy(groups,&defarea->Tagname[8],50); if(MatchFlags(tempcnode->DefaultGroup,groups)) break; } } /* If not found, we try to find the general default area */ if(!defarea) { for(defarea=(struct Area *)config.AreaList.First;defarea;defarea=defarea->Next) if(stricmp(defarea->Tagname,"DEFAULT")==0) break; } if(defarea) { struct TossNode *tnode; ulong c; uchar *forbiddenchars="\"#'`()*,./:;<>|"; uchar buf[100],buf2[100]; strcpy(buf,name); for(c=0;buf[c]!=0;c++) if(buf[c]<33 || buf[c]>126 || strchr(forbiddenchars,buf[c])) buf[c]='_'; /* Cannot create directory directly into temparea->Path. MakeDirectory checks for duplicate area names in the AreaList and would get confused */ MakeDirectory(buf2,80,defarea->Path,buf); strcpy(temparea->Path,buf2); if(!forcepassthru) temparea->Messagebase=defarea->Messagebase; strcpy(temparea->Description,defarea->Description); if(defarea->Flags & AREA_MANDATORY) temparea->Flags |= AREA_MANDATORY; if(defarea->Flags & AREA_DEFREADONLY) temparea->Flags |= AREA_DEFREADONLY; if(defarea->Flags & AREA_IGNOREDUPES) temparea->Flags |= AREA_IGNOREDUPES; if(defarea->Flags & AREA_IGNORESEENBY) temparea->Flags |= AREA_IGNORESEENBY; temparea->KeepDays=defarea->KeepDays; temparea->KeepNum=defarea->KeepNum; for(tnode=(struct TossNode *)defarea->TossNodes.First;tnode;tnode=tnode->Next) AddTossNode(temparea,tnode->ConfigNode,tnode->Flags); } GetDescription(name,tempcnode,temparea->Description); if(!active) temparea->Flags=AREA_UNCONFIRMED; strcpy(temparea->Tagname,name); temparea->Aka=tempaka; temparea->AreaType = AREATYPE_ECHOMAIL; if(tempcnode) { temparea->Group=tempcnode->DefaultGroup; AddTossNode(temparea,tempcnode,TOSSNODE_FEED); for(tempcnode=(struct ConfigNode *)config.CNodeList.First;tempcnode;tempcnode=tempcnode->Next) if(MatchFlags(temparea->Group,tempcnode->AddGroups)) { ushort flags; flags=0; if((temparea->Flags & AREA_DEFREADONLY) || MatchFlags(temparea->Group,tempcnode->ReadOnlyGroups)) flags=TOSSNODE_READONLY; AddTossNode(temparea,tempcnode,flags); } } config.changed=TRUE; temparea->changed=TRUE; return(temparea); } /**************************** Echomail *****************************/ bool FindNodes2D(struct jbList *list,struct Node4D *node) { struct Nodes2D *tmp; ushort c; for(tmp=(struct Nodes2D *)list->First;tmp;tmp=tmp->Next) for(c=0;cNodes;c++) if(tmp->Net[c]==node->Net && tmp->Node[c]==node->Node) return(TRUE); return(FALSE); } bool WriteBad(struct MemMessage *mm,uchar *reason) { struct Area *temparea; struct TextChunk *chunk; for(temparea=(struct Area *)config.AreaList.First;temparea;temparea=temparea->Next) if(temparea->AreaType == AREATYPE_BAD) break; if(!temparea) { LogWrite(2,TOSSINGERR,"No BAD area configured, message lost"); return(TRUE); } /* Insert a new textchunk with information first in the message */ if(!(chunk=(struct TextChunk *)osAlloc(sizeof(struct TextChunk)))) { nomem=TRUE; return(FALSE); } chunk->Next=(struct TextChunk *)mm->TextChunks.First; mm->TextChunks.First = (struct jbNode *)chunk; if(!mm->TextChunks.Last) mm->TextChunks.Last=(struct jbNode *)chunk; if(mm->Area[0]==0) { sprintf(chunk->Data,"DEST:%u:%u/%u.%u\x0d" "ORIG:%u:%u/%u.%u\x0d" "PKTORIG:%u:%u/%u.%u\x0d" "PKTDEST:%u:%u/%u.%u\x0d" "ERROR:%s\x0d", mm->DestNode.Zone, mm->DestNode.Net, mm->DestNode.Node, mm->DestNode.Point, mm->OrigNode.Zone, mm->OrigNode.Net, mm->OrigNode.Node, mm->OrigNode.Point, mm->PktOrig.Zone, mm->PktOrig.Net, mm->PktOrig.Node, mm->PktOrig.Point, mm->PktDest.Zone, mm->PktDest.Net, mm->PktDest.Node, mm->PktDest.Point, reason); chunk->Length=strlen(chunk->Data); } else { sprintf(chunk->Data,"AREA:%s\x0d" "PKTORIG:%u:%u/%u.%u\x0d" "PKTDEST:%u:%u/%u.%u\x0d" "ERROR:%s\x0d", mm->Area, mm->PktOrig.Zone, mm->PktOrig.Net, mm->PktOrig.Node, mm->PktOrig.Point, mm->PktDest.Zone, mm->PktDest.Net, mm->PktDest.Node, mm->PktDest.Point, reason); chunk->Length=strlen(chunk->Data); } if(temparea->Messagebase) { if(!((*temparea->Messagebase->importfunc)(mm,temparea))) return(FALSE); } /* Remove first chunk again */ chunk=(struct TextChunk *)mm->TextChunks.First; mm->TextChunks.First=(struct jbNode *)chunk->Next; if((struct TextChunk *)mm->TextChunks.Last == chunk) mm->TextChunks.Last = NULL; osFree(chunk); temparea->NewTexts++; return(TRUE); } bool AddNodePath(struct jbList *list,struct Node4D *node) { uchar buf[40],buf2[10]; struct Path *path; struct Node4D n4d; ushort lastnet,num; bool lastok; ulong jbcpos; lastok=FALSE; lastnet=0; /* Find last entry in Path */ path=(struct Path *)list->Last; if(path && path->Paths!=0) { num=path->Paths-1; jbcpos=0; while(jbstrcpy(buf,path->Path[num],40,&jbcpos)) { if(Parse4D(buf,&n4d)) { if(n4d.Net == 0) n4d.Net=lastnet; else lastnet=n4d.Net; lastok=TRUE; } else { lastok=FALSE; } } } /* Are we already in the PATH line? */ if(lastok) { if(n4d.Net == node->Net && n4d.Node == node->Node && n4d.Point == node->Point) return(TRUE); } /* Make address */ if(lastok && n4d.Net == node->Net) sprintf(buf,"%u",node->Node); else sprintf(buf,"%u/%u",node->Net,node->Node); if(node->Point != 0) { sprintf(buf2,".%u",node->Point); strcat(buf,buf2); } /* Add new */ path=(struct Path *)list->Last; if(path) { if(path->Paths != 0) { if(strlen(buf)+strlen(path->Path[path->Paths-1])<=70) { /* Add to old path */ strcat(path->Path[path->Paths-1]," "); strcat(path->Path[path->Paths-1],buf); return(TRUE); } } } if(path && path->Paths == PKT_NUMPATH) path=NULL; /* Chunk is full */ if(!path) { /* Alloc new path */ if(!(path=(struct Path *)osAlloc(sizeof(struct Path)))) { nomem=TRUE; return(FALSE); } jbAddNode(list,(struct jbNode *)path); path->Next=NULL; path->Paths=0; } /* Always net/node when a new line */ sprintf(path->Path[path->Paths],"%u/%u",node->Net,node->Node); if(node->Point != 0) { sprintf(buf2,".%u",node->Point); strcat(path->Path[path->Paths],buf2); } path->Paths++; return(TRUE); } uchar *StripRe(uchar *str) { for (;;) { if(strnicmp (str, "Re:", 3)==0) { str += 3; if (*str == ' ') str++; } else if(strnicmp (str, "Re^", 3)==0 && str[4]==':') { str += 5; if (*str == ' ') str++; } else if(strnicmp (str, "Re[", 3)==0 && str[4]==']' && str[5]==':') { str += 6; if (*str == ' ') str++; } else break; } return (str); } bool HandleEchomail(struct MemMessage *mm) { struct Area *temparea; struct TossNode *temptnode; struct AddNode *tmpaddnode; struct RemNode *tmpremnode; struct ConfigNode *tempcnode; mm->Type=PKTS_ECHOMAIL; /* Find orignode */ for(tempcnode=(struct ConfigNode *)config.CNodeList.First;tempcnode;tempcnode=tempcnode->Next) if(Compare4D(&mm->PktOrig,&tempcnode->Node)==0) break; /* Find area */ for(temparea=(struct Area *)config.AreaList.First;temparea;temparea=temparea->Next) if(stricmp(temparea->Tagname,mm->Area)==0) break; /* Auto-add */ if(!temparea) { if(tempcnode) temparea=AddArea(mm->Area,&mm->PktOrig,&mm->PktDest,tempcnode->Flags & NODE_AUTOADD,FALSE); else temparea=AddArea(mm->Area,&mm->PktOrig,&mm->PktDest,FALSE,FALSE); if(!temparea) return(FALSE); if(temparea->Flags & AREA_UNCONFIRMED) LogWrite(3,TOSSINGERR,"Unknown area %s",mm->Area); else LogWrite(3,TOSSINGINFO,"Unknown area %s -- auto-adding",mm->Area); } /* Don't toss in auto-added areas */ if(temparea->Flags & AREA_UNCONFIRMED) { toss_bad++; if(!WriteBad(mm,"Unknown area (auto-added but not confirmed)")) return(FALSE); return(TRUE); } /* Check if the node receives this area */ if(!(mm->Flags & MMFLAG_EXPORTED) && !(mm->Flags & MMFLAG_NOSECURITY)) { for(temptnode=(struct TossNode *)temparea->TossNodes.First;temptnode;temptnode=temptnode->Next) if(Compare4D(&temptnode->ConfigNode->Node,&mm->PktOrig)==0) break; if(!temptnode) { LogWrite(1,TOSSINGERR,"%lu:%lu/%lu.%lu doesn't receive %s", mm->PktOrig.Zone, mm->PktOrig.Net, mm->PktOrig.Node, mm->PktOrig.Point, mm->Area); toss_bad++; if(!WriteBad(mm,"Node does not receive this area")) return(FALSE); return(TRUE); } if(temptnode->Flags & TOSSNODE_READONLY) { LogWrite(1,TOSSINGERR,"%lu:%lu/%lu.%lu is not allowed to write in %s", mm->PktOrig.Zone, mm->PktOrig.Net, mm->PktOrig.Node, mm->PktOrig.Point, mm->Area); toss_bad++; if(!WriteBad(mm,"Node is not allowed to write in this area")) return(FALSE); return(TRUE); } } /* Remove all seen-by:s if the message comes from an other zone */ if(temparea->Aka->Node.Zone != mm->PktOrig.Zone && mm->SeenBy.First) jbFreeList(&mm->SeenBy); /* Check if a node already is in seen-by */ if((config.cfg_Flags & CFG_CHECKSEENBY) && !(temparea->Flags & AREA_IGNORESEENBY)) { for(temptnode=(struct TossNode *)temparea->TossNodes.First;temptnode;temptnode=temptnode->Next) { temptnode->ConfigNode->IsInSeenBy=FALSE; if(temptnode->ConfigNode->Node.Zone == temparea->Aka->Node.Zone) if(temptnode->ConfigNode->Node.Point==0) if(FindNodes2D(&mm->SeenBy,&temptnode->ConfigNode->Node)) temptnode->ConfigNode->IsInSeenBy=TRUE; } } /* Add nodes to seen-by */ for(temptnode=(struct TossNode *)temparea->TossNodes.First;temptnode;temptnode=temptnode->Next) if(temptnode->ConfigNode->Node.Point == 0 && temparea->Aka->Node.Zone == temptnode->ConfigNode->Node.Zone) if(!(temptnode->ConfigNode->Flags & NODE_PASSIVE)) if(!(temptnode->Flags & TOSSNODE_WRITEONLY)) { if(!mmAddNodes2DList(&mm->SeenBy,temptnode->ConfigNode->Node.Net,temptnode->ConfigNode->Node.Node)) return(FALSE); } /* Remove nodes specified in config from seen-by and path */ for(tmpremnode=(struct RemNode *)temparea->Aka->RemList.First;tmpremnode;tmpremnode=tmpremnode->Next) mmRemNodes2DListPat(&mm->SeenBy,&tmpremnode->NodePat); /* Add nodes specified in config to seen-by */ for(tmpaddnode=(struct AddNode *)temparea->Aka->AddList.First;tmpaddnode;tmpaddnode=tmpaddnode->Next) mmAddNodes2DList(&mm->SeenBy,tmpaddnode->Node.Net,tmpaddnode->Node.Node); /* Add own node to seen-by */ if(temparea->Aka->Node.Point == 0) { if(!mmAddNodes2DList(&mm->SeenBy,temparea->Aka->Node.Net,temparea->Aka->Node.Node)) return(FALSE); } /* Add own node to path */ if(temparea->Aka->Node.Point == 0 || (config.cfg_Flags & CFG_PATH3D)) { if(!AddNodePath(&mm->Path,&temparea->Aka->Node)) return(FALSE); } /* Dupecheck */ if(config.cfg_DupeMode!=DUPE_IGNORE && (mm->Flags & MMFLAG_TOSSED) && !(temparea->Flags & AREA_IGNOREDUPES)) { if(CheckDupe(mm)) { LogWrite(4,TOSSINGERR,"Duplicate message in %s",mm->Area); toss_dupes++; temparea->NewDupes++; if(tempcnode) tempcnode->Dupes++; if(config.cfg_DupeMode == DUPE_BAD) { if(!WriteBad(mm,"Duplicate message")) return(FALSE); } return(TRUE); } } if(!mmSortNodes2D(&mm->SeenBy)) return(FALSE); /* Filter */ if(!Filter(mm)) return(FALSE); if(mm->Flags & MMFLAG_KILL) return(TRUE); temparea->NewTexts++; /* Write to all nodes */ if(!(mm->Flags & MMFLAG_RESCANNED)) { /* not rescanned */ for(temptnode=(struct TossNode *)temparea->TossNodes.First;temptnode;temptnode=temptnode->Next) /* is not sender of packet */ if(Compare4D(&mm->PktOrig,&temptnode->ConfigNode->Node)!=0) /* is not passive */ if(!(temptnode->ConfigNode->Flags & NODE_PASSIVE)) /* is not write-only */ if(!(temptnode->Flags & TOSSNODE_WRITEONLY)) /* is not already in seen-by */ if(!(temptnode->ConfigNode->IsInSeenBy == TRUE && (config.cfg_Flags & CFG_CHECKSEENBY))) { if(!WriteEchoMail(mm,temptnode->ConfigNode,temparea->Aka)) return(FALSE); } } if(mm->Flags & MMFLAG_TWIT) return(TRUE); if(!(mm->Flags & MMFLAG_EXPORTED) && temparea->Messagebase) { toss_import++; if(config.cfg_Flags & CFG_STRIPRE) strcpy(mm->Subject,StripRe(mm->Subject)); /* Remove LOCAL flag if set and set SENT flag */ mm->Attr |= FLAG_SENT; mm->Attr &= ~(FLAG_LOCAL); if(!(*temparea->Messagebase->importfunc)(mm,temparea)) return(FALSE); } return(TRUE); } /******************************* netmail **********************************/ /* For loop-mail checking */ bool CheckFoundAka(uchar *str) { struct Node4D via4d; struct Aka *aka; if(!(strstr(str,":") && strstr(str,"/"))) return(FALSE); if(!Parse4D(str,&via4d)) return(FALSE); if(via4d.Zone==0 || via4d.Net==0) return(FALSE); for(aka=(struct Aka *)config.AkaList.First;aka;aka=aka->Next) if(Compare4D(&aka->Node,&via4d)==0) return(TRUE); return(FALSE); } bool IsLoopMail(struct MemMessage *mm) { struct TextChunk *tmp; ushort q; ulong c,d; for(tmp=(struct TextChunk *)mm->TextChunks.First;tmp;tmp=tmp->Next) { c=0; while(cLength) { for(d=c;dLength && tmp->Data[d]!=13;d++); if(tmp->Data[d]==13) d++; if(strncmp(&tmp->Data[c],"\x01Via",4)==0) { /* Is ^aVia line */ uchar via[200]; if(d-c<150) q=d-c; else q=150; strncpy(via,&tmp->Data[c],q); via[q]=0; if(strstr(via,"CrashMail")) { /* Is created by CrashMail */ uchar destbuf[20]; ushort u,v; v=0; for(u=0;via[u]!=0;u++) { if(via[u]==':' || via[u]=='/' || via[u]=='.' || (via[u]>='0' && via[u]<='9')) { if(v<19) destbuf[v++]=via[u]; } else { if(v!=0) { destbuf[v]=0; if(CheckFoundAka(destbuf)) return(TRUE); } v=0; } } if(v!=0) { destbuf[v]=0; if(CheckFoundAka(destbuf)) return(TRUE); } } } c=d; } } return(FALSE); } /* Bouncing and receipts */ bool Bounce(struct MemMessage *mm,uchar *reason,bool headeronly) { uchar buf[400],*tmpbuf; ulong c; struct Route *tmproute; struct MemMessage *tmpmm; struct TextChunk *chunk; struct Node4D n4d; if(mm->Flags & MMFLAG_AUTOGEN) { LogWrite(1,TOSSINGERR,"No bounce messages sent for messages created by CrashMail"); return(TRUE); } if(mm->Area[0] == 0) Copy4D(&n4d,&mm->OrigNode); else Copy4D(&n4d,&mm->Origin4D); for(tmproute=(struct Route *)config.RouteList.First;tmproute;tmproute=tmproute->Next) if(Compare4DPat(&tmproute->Pattern,&n4d)==0) break; if(!tmproute) { Print4D(&n4d,buf); LogWrite(1,TOSSINGERR,"Can't bounce message, no routing for %s",buf); return(TRUE); } if(!(tmpmm=mmAlloc())) return(FALSE); Copy4D(&tmpmm->DestNode,&n4d); Copy4D(&tmpmm->OrigNode,&tmproute->Aka->Node); strcpy(tmpmm->To,mm->From); strcpy(tmpmm->From,config.cfg_Sysop); strcpy(tmpmm->Subject,"Bounced message"); tmpmm->Attr=FLAG_PVT; MakeFidoDate(time(NULL),tmpmm->DateTime); tmpmm->Flags |= MMFLAG_AUTOGEN; MakeNetmailKludges(tmpmm); if(config.cfg_Flags & CFG_ADDTID) AddTID(tmpmm); strncpy(buf,reason,390); strcat(buf,"\x0d\x0d"); mmAddLine(tmpmm,buf); if(headeronly) mmAddLine(tmpmm,"This is the header of the message that was bounced:\x0d\x0d"); else mmAddLine(tmpmm,"This is the message that was bounced:\x0d\x0d"); if(mm->Area[0]) { sprintf(buf,"Area: %.80s\x0d",mm->Area); mmAddLine(tmpmm,buf); sprintf(buf,"From: %.40s (%u:%u/%u.%u)\x0d",mm->From, n4d.Zone, n4d.Net, n4d.Node, n4d.Point); mmAddLine(tmpmm,buf); sprintf(buf," To: %.40s\x0d",mm->To); mmAddLine(tmpmm,buf); } else { sprintf(buf,"From: %.40s (%u:%u/%u.%u)\x0d",mm->From, n4d.Zone, n4d.Net, n4d.Node, n4d.Point); mmAddLine(tmpmm,buf); sprintf(buf," To: %.40s (%u:%u/%u.%u)\x0d", mm->To,mm->DestNode.Zone, mm->DestNode.Net, mm->DestNode.Node, mm->DestNode.Point); mmAddLine(tmpmm,buf); } sprintf(buf,"Subj: %s\x0d",mm->Subject); mmAddLine(tmpmm,buf); sprintf(buf,"Date: %s\x0d\x0d",mm->DateTime); mmAddLine(tmpmm,buf); if(!headeronly) { for(chunk=(struct TextChunk *)mm->TextChunks.First;chunk;chunk=chunk->Next) { if(chunk->Length) { if(!(tmpbuf=(uchar *)osAlloc(chunk->Length))) { nomem=TRUE; mmFree(tmpmm); return(FALSE); } for(c=0;cLength;c++) { if(chunk->Data[c]==1) tmpbuf[c]='@'; else tmpbuf[c]=chunk->Data[c]; } mmAddBuf(&tmpmm->TextChunks,tmpbuf,chunk->Length); osFree(tmpbuf); } } } if(!HandleMessage(tmpmm)) { mmFree(tmpmm); return(FALSE); } mmFree(tmpmm); return(TRUE); } bool AnswerReceipt(struct MemMessage *mm) { uchar buf[400]; struct Route *tmproute; struct MemMessage *tmpmm; LogWrite(4,TOSSINGINFO,"Answering to a receipt request"); for(tmproute=(struct Route *)config.RouteList.First;tmproute;tmproute=tmproute->Next) if(Compare4DPat(&tmproute->Pattern,&mm->OrigNode)==0) break; if(!tmproute) { Print4D(&mm->OrigNode,buf); LogWrite(1,TOSSINGERR,"Can't send receipt, no routing for %s",buf); return(TRUE); } if(!(tmpmm=mmAlloc())) return(FALSE); Copy4D(&tmpmm->DestNode,&mm->OrigNode); Copy4D(&tmpmm->OrigNode,&tmproute->Aka->Node); strcpy(tmpmm->To,mm->From); strcpy(tmpmm->From,config.cfg_Sysop); strcpy(tmpmm->Subject,"Receipt"); tmpmm->Attr=FLAG_PVT | FLAG_IRRR; MakeFidoDate(time(NULL),tmpmm->DateTime); mm->Flags |= MMFLAG_AUTOGEN; MakeNetmailKludges(tmpmm); if(config.cfg_Flags & CFG_ADDTID) AddTID(tmpmm); sprintf(buf,"Your message to %s dated %s with the subject \"%s\" has reached its final " "destination. This message doesn't mean that the message has been read, it " "just tells you that it has arrived at this system.\x0d\x0d", mm->To,mm->DateTime,mm->Subject); mmAddLine(tmpmm,buf); if(!HandleMessage(tmpmm)) { mmFree(tmpmm); return(FALSE); } mmFree(tmpmm); return(TRUE); } bool AnswerAudit(struct MemMessage *mm) { uchar buf[200],auditbuf[500]; struct Route *tmproute,*destroute; struct MemMessage *tmpmm; struct Node4D n4d; LogWrite(4,TOSSINGINFO,"Answering to an audit request"); for(tmproute=(struct Route *)config.RouteList.First;tmproute;tmproute=tmproute->Next) if(Compare4DPat(&tmproute->Pattern,&mm->OrigNode)==0) break; if(!tmproute) { Print4D(&mm->OrigNode,buf); LogWrite(1,TOSSINGERR,"Can't send receipt, no routing for %s",buf); return(TRUE); } if(!(tmpmm=mmAlloc())) return(FALSE); Copy4D(&tmpmm->DestNode,&mm->OrigNode); Copy4D(&tmpmm->OrigNode,&tmproute->Aka->Node); strcpy(tmpmm->To,mm->From); strcpy(tmpmm->From,config.cfg_Sysop); strcpy(tmpmm->Subject,"Audit"); tmpmm->Attr=FLAG_PVT; MakeFidoDate(time(NULL),tmpmm->DateTime); tmpmm->Flags |= MMFLAG_AUTOGEN; MakeNetmailKludges(tmpmm); if(config.cfg_Flags & CFG_ADDTID) AddTID(tmpmm); for(destroute=(struct Route *)config.RouteList.First;destroute;destroute=destroute->Next) if(Compare4DPat(&destroute->Pattern,&mm->DestNode)==0) break; if(destroute) { ExpandNodePat(&destroute->DestPat,&mm->DestNode,&n4d); sprintf(auditbuf,"Your message to %s dated %s with the subject \"%s\" has just been " "routed to %u:%u/%u.%u by this system.\x0d\x0d", mm->To,mm->DateTime,mm->Subject, n4d.Zone,n4d.Net,n4d.Node,n4d.Point); } else { Copy4D(&n4d,&mm->DestNode); sprintf(auditbuf,"Your message to %s dated %s with the subject \"%s\" could not be " "routed since no routing for %u:%u/%u.%u was configured at this " "system. Message lost! \x0d\x0d", mm->To,mm->DateTime,mm->Subject, n4d.Zone,n4d.Net,n4d.Node,n4d.Point); } mmAddLine(tmpmm,auditbuf); if(!HandleMessage(tmpmm)) { mmFree(tmpmm); return(FALSE); } mmFree(tmpmm); return(TRUE); } /* Main netmail handling */ bool HandleNetmail(struct MemMessage *mm) { struct Area *tmparea; struct Aka *aka; struct ConfigNode *cnode,*pktcnode; struct ImportNode *inode; struct Route *tmproute; struct Node4D n4d,Dest4D; struct PatternNode *patternnode; struct AreaFixName *areafixname; struct TextChunk *tmpchunk,*chunk; bool istext; uchar buf[400],buf2[200],buf3[200],subjtemp[80]; ulong c,d,jbcpos; time_t t; struct tm *tp; ulong size; uchar oldtype; bool headeronly; /* Find orignode */ for(pktcnode=(struct ConfigNode *)config.CNodeList.First;pktcnode;pktcnode=pktcnode->Next) if(Compare4D(&mm->PktOrig,&pktcnode->Node)==0) break; /* Calculate size */ size=0; for(tmpchunk=(struct TextChunk *)mm->TextChunks.First;tmpchunk;tmpchunk=tmpchunk->Next) size+=tmpchunk->Length; /* Statistics */ if((mm->Flags & MMFLAG_TOSSED) && pktcnode) { pktcnode->GotNetmails++; pktcnode->GotNetmailBytes+=size; } /* Set zones if they are zero */ if(mm->DestNode.Zone == 0) mm->DestNode.Zone = mm->PktDest.Zone; if(mm->OrigNode.Zone == 0) mm->OrigNode.Zone = mm->PktOrig.Zone; /* Add CR if last line doesn't end with CR */ chunk=(struct TextChunk *)mm->TextChunks.First; if(chunk && chunk->Length!=0) { if(chunk->Data[chunk->Length-1] != 13 && chunk->Data[chunk->Length-1]) mmAddBuf(&mm->TextChunks,"\x0d",1); } /* Filter */ if(!Filter(mm)) return(FALSE); if(mm->Flags & MMFLAG_KILL) return(TRUE); /* Check if it is to me */ for(aka=(struct Aka *)config.AkaList.First;aka;aka=aka->Next) if(Compare4D(&mm->DestNode,&aka->Node)==0) break; if(aka) { /* AreaFix */ if(!(mm->Flags & MMFLAG_AUTOGEN)) { for(areafixname=(struct AreaFixName *)config.AreaFixList.First;areafixname;areafixname=areafixname->Next) if(stricmp(areafixname->Name,mm->To)==0) break; if(areafixname) { if(!AreaFix(mm)) return(FALSE); if(!(config.cfg_Flags & CFG_IMPORTAREAFIX)) return(TRUE); } } } /* Find correct area */ for(tmparea=(struct Area *)config.AreaList.First;tmparea;tmparea=tmparea->Next) if(tmparea->AreaType == AREATYPE_NETMAIL) { if(Compare4D(&tmparea->Aka->Node,&mm->DestNode)==0) break; for(inode=(struct ImportNode *)tmparea->TossNodes.First;inode;inode=inode->Next) if(Compare4D(&inode->Node,&mm->DestNode)==0) break; if(inode) break; } /* If no area was found but it is to one of the akas, take first netmail area */ /* Same if NOROUTE was specified in config */ if(!tmparea) { for(aka=(struct Aka *)config.AkaList.First;aka;aka=aka->Next) if(Compare4D(&mm->DestNode,&aka->Node)==0) break; if(aka || (config.cfg_Flags & CFG_NOROUTE)) { for(tmparea=(struct Area *)config.AreaList.First;tmparea;tmparea=tmparea->Next) if(tmparea->AreaType == AREATYPE_NETMAIL) break; } } if(tmparea) { /* Import netmail */ if(mm->Flags & MMFLAG_TWIT) return(TRUE); if(config.cfg_Flags & CFG_STRIPRE) strcpy(mm->Subject,StripRe(mm->Subject)); /* Import empty netmail? */ istext=TRUE; if(!(config.cfg_Flags & CFG_IMPORTEMPTYNETMAIL)) { istext=FALSE; for(chunk=(struct TextChunk *)mm->TextChunks.First;chunk && !istext;chunk=chunk->Next) for(c=0;cLength && !istext;) { if(chunk->Data[c]!=1) istext=TRUE; while(chunk->Data[c]!=13 && cLength) c++; if(chunk->Data[c]==13) c++; } } if(istext) { if(!(mm->Flags & MMFLAG_TOSSED)) LogWrite(3,TOSSINGINFO,"Importing message"); tmparea->NewTexts++; if(tmparea->Messagebase) { toss_import++; if(config.cfg_Flags & CFG_STRIPRE) strcpy(mm->Subject,StripRe(mm->Subject)); /* Remove LOCAL flag if set and set SENT flag */ mm->Attr |= FLAG_SENT; mm->Attr &= ~(FLAG_LOCAL); if(!(*tmparea->Messagebase->importfunc)(mm,tmparea)) return(FALSE); } } else { Print4D(&mm->OrigNode,buf); LogWrite(4,TOSSINGINFO,"Killed empty netmail from %s at %s",mm->From,buf); } if((mm->Attr & FLAG_RREQ) && (config.cfg_Flags & CFG_ANSWERRECEIPT)) { if(!AnswerReceipt(mm)) return(FALSE); } } else { /* Clear flags */ mm->Attr&=(FLAG_PVT|FLAG_CRASH|FLAG_FILEATTACH|FLAG_HOLD|FLAG_RREQ|FLAG_IRRR|FLAG_AUDIT); if(mm->Flags & MMFLAG_TOSSED) mm->Attr&=~(FLAG_CRASH|FLAG_HOLD); mm->Type = PKTS_NORMAL; if(mm->Attr & FLAG_CRASH) mm->Type=PKTS_CRASH; if(mm->Attr & FLAG_HOLD) mm->Type=PKTS_HOLD; /* File-attach? */ if((mm->Attr & FLAG_FILEATTACH) && !(config.cfg_Flags & CFG_NODIRECTATTACH)) { if(mm->Type == PKTS_NORMAL) mm->Type=PKTS_DIRECT; } /* Find route statement */ for(tmproute=(struct Route *)config.RouteList.First;tmproute;tmproute=tmproute->Next) if(Compare4DPat(&tmproute->Pattern,&mm->DestNode)==0) break; if(!tmproute) { LogWrite(1,TOSSINGERR,"No routing configured for %lu:%lu/%lu.%lu - message lost", mm->DestNode.Zone, mm->DestNode.Net, mm->DestNode.Node, mm->DestNode.Point); toss_bad++; if(!WriteBad(mm,"No routing for destination node")) return(FALSE); return(TRUE); } /* Set destination */ if(mm->Type == PKTS_NORMAL) { uchar buf1[50],buf2[50],buf3[50]; Print4DPat(&tmproute->Pattern,buf1); Print4DPat(&tmproute->DestPat,buf2); Print4D(&tmproute->Aka->Node,buf3); LogWrite(6,DEBUG,"Uses this route statement: ROUTE \"%s\" \"%s\" \"%s\"",buf1,buf2,buf3); ExpandNodePat(&tmproute->DestPat,&mm->DestNode,&Dest4D); } else { Copy4D(&Dest4D,&mm->DestNode); } /* Change */ oldtype=mm->Type; mm->Type=ChangeType(&Dest4D,mm->Type); if(mm->Type != oldtype) { LogWrite(4,TOSSINGINFO,"Changed priority for netmail to %lu:%lu/%lu.%lu from %s to %s", Dest4D.Zone,Dest4D.Net,Dest4D.Node,Dest4D.Point, prinames[oldtype],prinames[mm->Type]); } if(Dest4D.Point != 0) { if(mm->Type == PKTS_DIRECT || mm->Type == PKTS_CRASH) { Dest4D.Point=0; LogWrite(4,TOSSINGINFO,"Cannot send %s to a point, sending to %lu:%lu/%lu.%lu instead", prinames[mm->Type],Dest4D.Zone,Dest4D.Net,Dest4D.Node,Dest4D.Point); } } /* Check for loopmail */ if(config.cfg_LoopMode != LOOP_IGNORE && !(mm->Flags & MMFLAG_EXPORTED)) { if(IsLoopMail(mm)) { LogWrite(1,TOSSINGERR,"Possible loopmail detected: Received from %lu:%lu/%lu.%lu, to %lu:%lu/%lu.%lu", mm->PktOrig.Zone, mm->PktOrig.Net, mm->PktOrig.Node, mm->PktOrig.Point, mm->DestNode.Zone, mm->DestNode.Net, mm->DestNode.Node, mm->DestNode.Point); if(config.cfg_LoopMode == LOOP_LOGBAD) { struct MemMessage *tmpmm; struct TextChunk *tmp; /* Make a copy of the message with only kludge lines */ if(!(tmpmm=mmAlloc())) return(FALSE); Copy4D(&tmpmm->PktOrig,&mm->PktOrig); Copy4D(&tmpmm->PktDest,&mm->PktDest); Copy4D(&tmpmm->OrigNode,&mm->OrigNode); Copy4D(&tmpmm->DestNode,&mm->DestNode); strcpy(tmpmm->Area,mm->Area); strcpy(tmpmm->To,mm->To); strcpy(tmpmm->From,mm->From); strcpy(tmpmm->Subject,mm->Subject); strcpy(tmpmm->DateTime,mm->DateTime); strcpy(tmpmm->MSGID,mm->MSGID); strcpy(tmpmm->REPLY,mm->REPLY); tmpmm->Attr=mm->Attr; tmpmm->Cost=mm->Cost; tmpmm->Type=mm->Type; tmpmm->Flags=mm->Flags; for(tmp=(struct TextChunk *)mm->TextChunks.First;tmp;tmp=tmp->Next) { c=0; while(cLength) { for(d=c;dLength && tmp->Data[d]!=13;d++); if(tmp->Data[d]==13) d++; if(tmp->Data[c]==1) { tmp->Data[c]='@'; mmAddBuf(&tmpmm->TextChunks,&tmp->Data[c],d-c); tmp->Data[c]=1; } c=d; } } toss_bad++; if(!WriteBad(tmpmm,"Possible loopmail")) return(FALSE); mmFree(tmpmm); } } } /* Bounce if not in nodelist */ if(config.cfg_NodelistType) { for(patternnode=(struct PatternNode *)config.BounceList.First;patternnode;patternnode=patternnode->Next) if(Compare4DPat(&patternnode->Pattern,&mm->DestNode)==0) break; if(patternnode) { struct Node4D node; Copy4D(&node,&mm->DestNode); node.Point=0; if(!(*config.cfg_NodelistType->nlCheckNode)(&node)) { LogWrite(3,TOSSINGERR,"Bounced message from %u:%u/%u.%u to %u:%u/%u.%u -- not in nodelist", mm->OrigNode.Zone, mm->OrigNode.Net, mm->OrigNode.Node, mm->OrigNode.Point, mm->DestNode.Zone, mm->DestNode.Net, mm->DestNode.Node, mm->DestNode.Point); sprintf(buf, "Warning! Your message has been bounced because the node %u:%u/%u doesn't exist in the nodelist.", mm->DestNode.Zone, mm->DestNode.Net, mm->DestNode.Node); headeronly=FALSE; if(config.cfg_Flags & CFG_BOUNCEHEADERONLY) headeronly=TRUE; if(!Bounce(mm,buf,headeronly)) return(FALSE); return(TRUE); } } } /* Bounce if unconfigured point */ if(config.cfg_Flags & CFG_BOUNCEPOINTS) { Copy4D(&n4d,&mm->DestNode); n4d.Point=0; for(aka=(struct Aka *)config.AkaList.First;aka;aka=aka->Next) { if(Compare4D(&aka->Node,&n4d)==0 && aka->Node.Point==0) { for(cnode=(struct ConfigNode *)config.CNodeList.First;cnode;cnode=cnode->Next) if(Compare4D(&cnode->Node,&mm->DestNode)==0) break; if(!cnode) { LogWrite(3,TOSSINGERR,"Bounced message from %u:%u/%u.%u to %u:%u/%u.%u -- unknown point", mm->OrigNode.Zone, mm->OrigNode.Net, mm->OrigNode.Node, mm->OrigNode.Point, mm->DestNode.Zone, mm->DestNode.Net, mm->DestNode.Node, mm->DestNode.Point); sprintf(buf,"Warning! Your message has been bounced because the point %u:%u/%u.%u doesn't exist.", mm->DestNode.Zone, mm->DestNode.Net, mm->DestNode.Node, mm->DestNode.Point); headeronly=FALSE; if(config.cfg_Flags & CFG_BOUNCEHEADERONLY) headeronly=TRUE; if(!Bounce(mm,buf,headeronly)) return(FALSE); return(TRUE); } } } } /* Handle file-attach */ if(mm->Attr & FLAG_FILEATTACH) { LogWrite(6,DEBUG,"Netmail is fileattach"); if(!(mm->Flags & MMFLAG_EXPORTED)) { for(patternnode=(struct PatternNode *)config.FileAttachList.First;patternnode;patternnode=patternnode->Next) if(Compare4DPat(&patternnode->Pattern,&mm->DestNode)==0) break; if(!patternnode) { LogWrite(3,TOSSINGERR,"Refused to route file-attach from %lu:%lu/%lu.%lu to %lu:%lu/%lu.%lu",mm->OrigNode.Zone,mm->OrigNode.Net,mm->OrigNode.Node,mm->OrigNode.Point, mm->DestNode.Zone,mm->DestNode.Net,mm->DestNode.Node,mm->DestNode.Point); sprintf(buf,"Warning! Your message has been bounced because because routing of file-attaches to %u:%u/%u.%u is not allowed.", mm->DestNode.Zone,mm->DestNode.Net,mm->DestNode.Node,mm->DestNode.Point); headeronly=FALSE; if(config.cfg_Flags & CFG_BOUNCEHEADERONLY) headeronly=TRUE; if(!Bounce(mm,buf,headeronly)) return(FALSE); return(TRUE); } } strcpy(subjtemp,mm->Subject); mm->Subject[0]=0; for(c=0;subjtemp[c];c++) { if(subjtemp[c]==',') subjtemp[c]=' '; if(subjtemp[c]=='\\') subjtemp[c]='/'; } jbcpos=0; while(jbstrcpy(buf,subjtemp,80,&jbcpos)) { if(mm->Subject[0] != 0) strcat(mm->Subject," "); strcat(mm->Subject,GetFilePart(buf)); LogWrite(4,TOSSINGINFO,"Routing file %s to %lu:%lu/%lu.%lu",GetFilePart(buf),Dest4D.Zone,Dest4D.Net,Dest4D.Node,Dest4D.Point); if((mm->Flags & MMFLAG_EXPORTED)) { if(osExists(buf)) { MakeFullPath(config.cfg_PacketDir,GetFilePart(buf),buf2,200); copyfile(buf,buf2); if(nomem || ioerror) return(FALSE); AddFlow(buf2,&Dest4D,mm->Type,FLOW_DELETE); } else { AddFlow(buf,&Dest4D,mm->Type,FLOW_NONE); } } else { MakeFullPath(config.cfg_Inbound,GetFilePart(buf),buf2,200); MakeFullPath(config.cfg_PacketDir,GetFilePart(buf),buf3,200); if(movefile(buf2,buf3)) { AddFlow(buf3,&Dest4D,mm->Type,FLOW_DELETE); } else { AddFlow(buf2,&Dest4D,mm->Type,FLOW_DELETE); } } } } time(&t); tp = localtime(&t); Print4D(&tmproute->Aka->Node,buf2); sprintf(buf,"\x01Via %s @%04u%02u%02u.%02u%02u%02u CrashMail II/" OS_PLATFORM_NAME " " VERSION "\x0d", buf2, tp->tm_year+1900, tp->tm_mon+1, tp->tm_mday, tp->tm_hour, tp->tm_min, tp->tm_sec); mmAddLine(mm,buf); if(mm->Type == PKTS_NORMAL) { LogWrite(5,TOSSINGINFO,"Routing message to %lu:%lu/%lu.%lu via %lu:%lu/%lu.%lu", mm->DestNode.Zone, mm->DestNode.Net, mm->DestNode.Node, mm->DestNode.Point, Dest4D.Zone, Dest4D.Net, Dest4D.Node, Dest4D.Point); } else { LogWrite(5,TOSSINGINFO,"Sending message directly to %lu:%lu/%lu.%lu", Dest4D.Zone, Dest4D.Net, Dest4D.Node, Dest4D.Point); } if(!WriteNetMail(mm,&Dest4D,tmproute->Aka)) return(FALSE); if((mm->Attr & FLAG_AUDIT) && (config.cfg_Flags & CFG_ANSWERAUDIT) && (mm->Flags & MMFLAG_TOSSED)) { if(!AnswerAudit(mm)) return(FALSE); } toss_route++; } return(TRUE); } /******************************* end netmail **********************************/ /********************************** Rescan *******************************/ bool HandleRescan(struct MemMessage *mm) { struct Area *temparea; rescan_total++; /* Find area */ for(temparea=(struct Area *)config.AreaList.First;temparea;temparea=temparea->Next) if(stricmp(temparea->Tagname,mm->Area)==0) break; /* Add own node to seen-by to be on the safe side */ if(temparea->Aka->Node.Point == 0) { if(!mmAddNodes2DList(&mm->SeenBy,temparea->Aka->Node.Net,temparea->Aka->Node.Node)) return(FALSE); } /* Add destination node to seen-by to be on the safe side */ if(RescanNode->Node.Point == 0) { if(!mmAddNodes2DList(&mm->SeenBy,RescanNode->Node.Net,RescanNode->Node.Node)) return(FALSE); } /* Add own node to path */ if(temparea->Aka->Node.Point == 0 || (config.cfg_Flags & CFG_PATH3D)) { if(!AddNodePath(&mm->Path,&temparea->Aka->Node)) return(FALSE); } if(!mmSortNodes2D(&mm->SeenBy)) return(FALSE); if(!WriteEchoMail(mm,RescanNode,temparea->Aka)) return(FALSE); return(TRUE); } crashmail-0.71/src/crashmail/handle.h0100644000000000000000000000060507763705065016261 0ustar rootrootbool HandleMessage(struct MemMessage *mm); bool HandleRescan(struct MemMessage *mm); struct Area *AddArea(uchar *name,struct Node4D *node,struct Node4D *mynode,ulong active,ulong forcepassthru); bool AddTossNode(struct Area *area,struct ConfigNode *cnode,ushort flags); bool WriteBad(struct MemMessage *mm,uchar *reason); bool Bounce(struct MemMessage *mm,uchar *reason,bool headeronly); crashmail-0.71/src/crashmail/stats.c0100644000000000000000000001161507300264670016147 0ustar rootroot#include "crashmail.h" #define STATS_IDENTIFIER "CST3" struct DiskAreaStats { uchar Tagname[80]; struct Node4D Aka; uchar Group; uchar fill_to_make_even; /* Just ignore this one */ ulong TotalTexts; ushort Last8Days[8]; ulong Dupes; time_t FirstTime; time_t LastTime; }; struct DiskNodeStats { struct Node4D Node; ulong GotNetmails; ulong GotNetmailBytes; ulong SentNetmails; ulong SentNetmailBytes; ulong GotEchomails; ulong GotEchomailBytes; ulong SentEchomails; ulong SentEchomailBytes; ulong Dupes; time_t FirstTime; }; bool WriteStats(uchar *file) { struct Area *area; struct ConfigNode *cnode; struct DiskAreaStats dastat; struct DiskNodeStats dnstat; osFile fh; ulong areas,nodes; if(!(fh=osOpen(file,MODE_NEWFILE))) { ulong 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(ulong)); osWrite(fh,&areas,sizeof(ulong)); 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(ushort)*8); Copy4D(&dastat.Aka,&area->Aka->Node); dastat.Group=area->Group; osWrite(fh,&dastat,sizeof(struct DiskAreaStats)); } } } osWrite(fh,&nodes,sizeof(ulong)); 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(uchar *file) { struct Area *area; struct ConfigNode *cnode; struct DiskAreaStats dastat; struct DiskNodeStats dnstat; ulong c,num; osFile fh; uchar 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(ulong)); osRead(fh,&num,sizeof(ulong)); c=0; while(cNext) 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(ushort)*8); } c++; } osRead(fh,&num,sizeof(ulong)); c=0; while(cNext) 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); } crashmail-0.71/src/crashmail/stats.h0100644000000000000000000000007307300264670016150 0ustar rootrootbool ReadStats(uchar *file); bool WriteStats(uchar *file); crashmail-0.71/src/crashmail/nl_cmnl.c0100644000000000000000000000204107300264670016424 0ustar rootroot#include "crashmail.h" #include "cmnllib/cmnllib.h" osFile nlfh; bool cmnl_nlStart(uchar *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); } crashmail-0.71/src/crashmail/nl_cmnl.h0100644000000000000000000000027207300264670016435 0ustar rootrootbool cmnl_nlStart(uchar *errbuf); void cmnl_nlEnd(void); bool cmnl_nlCheckNode(struct Node4D *node); long cmnl_nlGetHub(struct Node4D *node); long cmnl_nlGetRegion(struct Node4D *node); crashmail-0.71/src/crashmail/config.c0100644000000000000000000017124607763451736016303 0ustar rootroot#include "crashmail.h" extern uchar *config_version; bool CorrectFlags(uchar *flags) { ulong c; for(c=0;c'Z') return(FALSE); } return(TRUE); } uchar cfgbuf[4000]; bool ReadConfig(uchar *filename,struct Config *cfg,short *seconderr,ulong *cfgline,uchar *cfgerr) { uchar buf2[200],cfgword[30]; ulong c,d,jbcpos; osFile cfgfh; struct Aka *tmpaka, *LastAka=NULL; struct ConfigNode *tmpnode, *LastCNode=NULL; struct Area *tmparea, *LastArea=NULL; struct Packer *tmppacker, *LastPacker=NULL; struct Route *tmproute; struct ImportNode *tmpinode; struct PatternNode *tmppatternnode; struct Change *tmpchange; struct AreaFixName *tmpareafixname; struct Arealist *tmparealist; struct Filter *tmpfilter, *LastFilter=NULL; struct Command *tmpcommand; struct AddNode *tmpaddnode; struct RemNode *tmpremnode; struct TossNode *tmptnode; struct BannedNode *tmpbnode; struct Node4D tmp4d; ushort flags; cfg->changed=FALSE; mystrncpy(cfg->filename,filename,100); *cfgline=0; if(!(cfgfh=osOpen(filename,MODE_OLDFILE))) { *seconderr=READCONFIG_NOT_FOUND; return(FALSE); } *seconderr=READCONFIG_INVALID; while(osFGets(cfgfh,cfgbuf,4000)) { jbcpos=0; (*cfgline)++; jbstrcpy(cfgword,cfgbuf,30,&jbcpos); if(stricmp(cfgword,"AKA")==0) { if(!(tmpaka=(struct Aka *)osAllocCleared(sizeof(struct Aka)))) { *seconderr=READCONFIG_NO_MEM; osClose(cfgfh); return(FALSE); } jbAddNode(&cfg->AkaList,(struct jbNode *)tmpaka); LastAka=tmpaka; if(!(jbstrcpy(buf2,cfgbuf,200,&jbcpos))) { strcpy(cfgerr,"Missing argument"); osClose(cfgfh); return(FALSE); } if(!(Parse4D(buf2,&LastAka->Node))) { sprintf(cfgerr,"Invalid node number \"%s\"",buf2); osClose(cfgfh); return(FALSE); } jbNewList(&LastAka->AddList); jbNewList(&LastAka->RemList); } else if(stricmp(cfgword,"ADDNODE")==0) { if(!LastAka) { strcpy(cfgerr,"No previous AKA line"); osClose(cfgfh); return(FALSE); } while(jbstrcpy(buf2,cfgbuf,100,&jbcpos)) { if(!(tmpaddnode=(struct AddNode *)osAllocCleared(sizeof(struct AddNode)))) { *seconderr=READCONFIG_NO_MEM; osClose(cfgfh); return(FALSE); } jbAddNode(&LastAka->AddList,(struct jbNode *)tmpaddnode); if(!(Parse4D(buf2,&tmpaddnode->Node))) { sprintf(cfgerr,"Invalid node number \"%s\"",buf2); osClose(cfgfh); return(FALSE); } } } else if(stricmp(cfgword,"REMNODE")==0) { if(!LastAka) { strcpy(cfgerr,"No previous AKA line"); osClose(cfgfh); return(FALSE); } while(jbstrcpy(buf2,cfgbuf,100,&jbcpos)) { if(!(tmpremnode=(struct RemNode *)osAllocCleared(sizeof(struct RemNode)))) { *seconderr=READCONFIG_NO_MEM; osClose(cfgfh); return(FALSE); } jbAddNode(&LastAka->RemList,(struct jbNode *)tmpremnode); if(!Parse2DPat(buf2,&tmpremnode->NodePat)) { sprintf(cfgerr,"Invalid node pattern \"%s\"",buf2); osClose(cfgfh); return(FALSE); } } } else if(stricmp(cfgword,"DOMAIN")==0) { if(!LastAka) { strcpy(cfgerr,"No previous AKA line"); osClose(cfgfh); return(FALSE); } if(!(jbstrcpy(LastAka->Domain,cfgbuf,200,&jbcpos))) { strcpy(cfgerr,"Missing argument"); osClose(cfgfh); return(FALSE); } } else if(stricmp(cfgword,"GROUPNAME")==0) { if(!(jbstrcpy(buf2,cfgbuf,2,&jbcpos))) { strcpy(cfgerr,"Missing argument"); osClose(cfgfh); return(FALSE); } if(!CorrectFlags(buf2)) { sprintf(cfgerr,"Invalid group \"%s\"",buf2); osClose(cfgfh); return(FALSE); } if(!(jbstrcpy(cfg->cfg_GroupNames[buf2[0]-'A'],cfgbuf,80,&jbcpos))) { strcpy(cfgerr,"Missing argument"); osClose(cfgfh); return(FALSE); } } else if(stricmp(cfgword,"NODE")==0) { if(!(tmpnode=(struct ConfigNode *)osAllocCleared(sizeof(struct ConfigNode)))) { *seconderr=READCONFIG_NO_MEM; osClose(cfgfh); return(FALSE); } jbNewList(&tmpnode->RemoteAFList); jbAddNode(&cfg->CNodeList,(struct jbNode *)tmpnode); LastCNode=tmpnode; if(!(jbstrcpy(buf2,cfgbuf,200,&jbcpos))) { strcpy(cfgerr,"Missing argument"); osClose(cfgfh); return(FALSE); } if(!(Parse4D(buf2,&LastCNode->Node))) { sprintf(cfgerr,"Invalid node number \"%s\"",buf2); osClose(cfgfh); return(FALSE); } if(!(jbstrcpy(buf2,cfgbuf,10,&jbcpos))) { strcpy(cfgerr,"Missing argument"); osClose(cfgfh); return(FALSE); } tmppacker=NULL; if(buf2[0]!=0) { for(tmppacker=(struct Packer *)cfg->PackerList.First;tmppacker;tmppacker=tmppacker->Next) if(stricmp(buf2,tmppacker->Name)==0) break; if(!tmppacker) { sprintf(cfgerr,"Unknown packer \"%s\"",buf2); osClose(cfgfh); return(FALSE); } } LastCNode->Packer=tmppacker; if(!(jbstrcpy(LastCNode->PacketPW,cfgbuf,9,&jbcpos))) { strcpy(cfgerr,"Missing argument"); osClose(cfgfh); return(FALSE); } LastCNode->EchomailPri=PKTS_NORMAL; while(jbstrcpy(buf2,cfgbuf,200,&jbcpos)) { if(stricmp(buf2,"NOTIFY")==0) LastCNode->Flags|=NODE_NOTIFY; else if(stricmp(buf2,"PASSIVE")==0) LastCNode->Flags|=NODE_PASSIVE; else if(stricmp(buf2,"NOSEENBY")==0) LastCNode->Flags|=NODE_NOSEENBY; else if(stricmp(buf2,"TINYSEENBY")==0) LastCNode->Flags|=NODE_TINYSEENBY; else if(stricmp(buf2,"FORWARDREQ")==0) LastCNode->Flags|=NODE_FORWARDREQ; else if(stricmp(buf2,"PACKNETMAIL")==0) LastCNode->Flags|=NODE_PACKNETMAIL; else if(stricmp(buf2,"SENDAREAFIX")==0) LastCNode->Flags|=NODE_SENDAREAFIX; else if(stricmp(buf2,"SENDTEXT")==0) LastCNode->Flags|=NODE_SENDTEXT; else if(stricmp(buf2,"AUTOADD")==0) LastCNode->Flags|=NODE_AUTOADD; else if(stricmp(buf2,"CRASH")==0) LastCNode->EchomailPri=PKTS_CRASH; else if(stricmp(buf2,"DIRECT")==0) LastCNode->EchomailPri=PKTS_DIRECT; else if(stricmp(buf2,"HOLD")==0) LastCNode->EchomailPri=PKTS_HOLD; else { sprintf(cfgerr,"Unknown switch \"%s\"",buf2); osClose(cfgfh); return(FALSE); } } } else if(stricmp(cfgword,"PKTFROM")==0) { if(!LastCNode) { strcpy(cfgerr,"No previous NODE line"); osClose(cfgfh); return(FALSE); } LastCNode->Flags|=NODE_PKTFROM; if(!(jbstrcpy(buf2,cfgbuf,200,&jbcpos))) { strcpy(cfgerr,"Missing argument"); osClose(cfgfh); return(FALSE); } if(!(Parse4D(buf2,&LastCNode->PktFrom))) { sprintf(cfgerr,"Invalid node number \"%s\"",buf2); osClose(cfgfh); return(FALSE); } } else if(stricmp(cfgword,"AREAFIXINFO")==0) { if(!LastCNode) { strcpy(cfgerr,"No previous NODE line"); osClose(cfgfh); return(FALSE); } if(!(jbstrcpy(LastCNode->AreafixPW,cfgbuf,40,&jbcpos))) { strcpy(cfgerr,"Missing argument"); osClose(cfgfh); return(FALSE); } if(jbstrcpy(LastCNode->Groups,cfgbuf,70,&jbcpos)) { if(!CorrectFlags(LastCNode->Groups)) { sprintf(cfgerr,"Invalid groups \"%s\"",LastCNode->Groups); osClose(cfgfh); return(FALSE); } } if(jbstrcpy(LastCNode->ReadOnlyGroups,cfgbuf,70,&jbcpos)) { if(!CorrectFlags(LastCNode->ReadOnlyGroups)) { sprintf(cfgerr,"Invalid groups \"%s\"",LastCNode->ReadOnlyGroups); osClose(cfgfh); return(FALSE); } } if(jbstrcpy(LastCNode->AddGroups,cfgbuf,70,&jbcpos)) { if(!CorrectFlags(LastCNode->AddGroups)) { sprintf(cfgerr,"Invalid groups \"%s\"",LastCNode->AddGroups); osClose(cfgfh); return(FALSE); } } } else if(stricmp(cfgword,"DEFAULTGROUP")==0) { if(!LastCNode) { strcpy(cfgerr,"No previous NODE line"); osClose(cfgfh); return(FALSE); } if(!(jbstrcpy(buf2,cfgbuf,2,&jbcpos))) { strcpy(cfgerr,"Missing argument"); osClose(cfgfh); return(FALSE); } if(!CorrectFlags(buf2)) { sprintf(cfgerr,"Invalid group \"%s\"",buf2); osClose(cfgfh); return(FALSE); } LastCNode->DefaultGroup=buf2[0]; } else if(stricmp(cfgword,"AREA")==0 || stricmp(cfgword,"NETMAIL")==0 || stricmp(cfgword,"LOCALAREA")==0) { if(!(tmparea=(struct Area *)osAllocCleared(sizeof(struct Area)))) { *seconderr=READCONFIG_NO_MEM; osClose(cfgfh); return(FALSE); } jbNewList(&tmparea->TossNodes); jbNewList(&tmparea->BannedNodes); jbAddNode(&cfg->AreaList,(struct jbNode *)tmparea); LastArea=tmparea; if(!(jbstrcpy(LastArea->Tagname,cfgbuf,80,&jbcpos))) { strcpy(cfgerr,"Missing argument"); osClose(cfgfh); return(FALSE); } if(!(jbstrcpy(buf2,cfgbuf,200,&jbcpos))) { strcpy(cfgerr,"Missing argument"); osClose(cfgfh); return(FALSE); } if(!(Parse4D(buf2,&tmp4d))) { sprintf(cfgerr,"Invalid node number \"%s\"",buf2); osClose(cfgfh); return(FALSE); } for(tmpaka=(struct Aka *)cfg->AkaList.First;tmpaka;tmpaka=tmpaka->Next) if(Compare4D(&tmp4d,&tmpaka->Node)==0) break; if(!tmpaka) { sprintf(cfgerr,"Unknown AKA \"%s\"",buf2); osClose(cfgfh); return(FALSE); } LastArea->Aka=tmpaka; if(jbstrcpy(buf2,cfgbuf,200,&jbcpos)) { int c; for(c=0;AvailMessagebases[c].name;c++) if(stricmp(buf2,AvailMessagebases[c].name)==0) break; if(AvailMessagebases[c].name) { LastArea->Messagebase= &AvailMessagebases[c]; } else { sprintf(cfgerr,"Unknown messagebase format \"%s\"",buf2); osClose(cfgfh); return(FALSE); } if(!(jbstrcpy(LastArea->Path,cfgbuf,80,&jbcpos))) { strcpy(cfgerr,"Missing argument"); osClose(cfgfh); return(FALSE); } } if(stricmp(cfgword,"NETMAIL")==0) { if(!LastArea->Messagebase) { sprintf(cfgerr,"Netmail area cannot be pass-through"); osClose(cfgfh); return(FALSE); } LastArea->AreaType=AREATYPE_NETMAIL; } else if(stricmp(cfgword,"LOCALAREA")==0) { if(!LastArea->Messagebase) { sprintf(cfgerr,"Local area cannot be pass-through"); osClose(cfgfh); return(FALSE); } LastArea->AreaType=AREATYPE_LOCAL; } else if(stricmp(LastArea->Tagname,"BAD")==0) { if(LastArea->Path[0]==0) { sprintf(cfgerr,"BAD area cannot be pass-through"); osClose(cfgfh); return(FALSE); } LastArea->AreaType=AREATYPE_BAD; } else if(stricmp(LastArea->Tagname,"DEFAULT")==0 || strnicmp(LastArea->Tagname,"DEFAULT_",8)==0) { LastArea->AreaType=AREATYPE_DEFAULT; } else { LastArea->AreaType=AREATYPE_ECHOMAIL; } } else if(stricmp(cfgword,"UNCONFIRMED")==0) { if(!LastArea) { strcpy(cfgerr,"No previous AREA line"); osClose(cfgfh); return(FALSE); } LastArea->Flags|=AREA_UNCONFIRMED; } else if(stricmp(cfgword,"MANDATORY")==0) { if(!LastArea) { strcpy(cfgerr,"No previous AREA line"); osClose(cfgfh); return(FALSE); } LastArea->Flags|=AREA_MANDATORY; } else if(stricmp(cfgword,"DEFREADONLY")==0) { if(!LastArea) { strcpy(cfgerr,"No previous AREA line"); osClose(cfgfh); return(FALSE); } LastArea->Flags|=AREA_DEFREADONLY; } else if(stricmp(cfgword,"IGNOREDUPES")==0) { if(!LastArea) { strcpy(cfgerr,"No previous AREA line"); osClose(cfgfh); return(FALSE); } LastArea->Flags|=AREA_IGNOREDUPES; } else if(stricmp(cfgword,"IGNORESEENBY")==0) { if(!LastArea) { strcpy(cfgerr,"No previous AREA line"); osClose(cfgfh); return(FALSE); } LastArea->Flags|=AREA_IGNORESEENBY; } else if(stricmp(cfgword,"EXPORT")==0) { struct Node4D tpl4d; if(!LastArea) { strcpy(cfgerr,"No previous AREA line"); osClose(cfgfh); return(FALSE); } if(LastArea->AreaType != AREATYPE_ECHOMAIL && LastArea->AreaType != AREATYPE_DEFAULT) { strcpy(cfgerr,"Not an echomail or default area"); osClose(cfgfh); return(FALSE); } tpl4d.Zone=0; tpl4d.Net=0; tpl4d.Node=0; tpl4d.Point=0; while(jbstrcpy(buf2,cfgbuf,100,&jbcpos)) { flags=0; if(buf2[0]=='!') { flags=TOSSNODE_READONLY; strcpy(buf2,&buf2[1]); } if(buf2[0]=='@') { flags=TOSSNODE_WRITEONLY; strcpy(buf2,&buf2[1]); } if(buf2[0]=='%') { flags=TOSSNODE_FEED; strcpy(buf2,&buf2[1]); } if(!(Parse4DTemplate(buf2,&tmp4d,&tpl4d))) { sprintf(cfgerr,"Invalid node number \"%s\"",buf2); osClose(cfgfh); return(FALSE); } Copy4D(&tpl4d,&tmp4d); tpl4d.Point=0; for(tmpnode=(struct ConfigNode *)cfg->CNodeList.First;tmpnode;tmpnode=tmpnode->Next) if(Compare4D(&tmp4d,&tmpnode->Node)==0) break; if(!tmpnode) { sprintf(cfgerr,"Unconfigured node \"%s\"",buf2); osClose(cfgfh); return(FALSE); } if(!(tmptnode=(struct TossNode *)osAllocCleared(sizeof(struct TossNode)))) { *seconderr=READCONFIG_NO_MEM; osClose(cfgfh); return(FALSE); } jbAddNode(&LastArea->TossNodes,(struct jbNode *)tmptnode); tmptnode->ConfigNode=tmpnode; tmptnode->Flags=flags; } } else if(stricmp(cfgword,"IMPORT")==0) { if(!LastArea) { strcpy(cfgerr,"No previous AREA line"); osClose(cfgfh); return(FALSE); } if(LastArea->AreaType != AREATYPE_NETMAIL) { strcpy(cfgerr,"Not a netmail area"); osClose(cfgfh); return(FALSE); } while(jbstrcpy(buf2,cfgbuf,100,&jbcpos)) { if(!(tmpinode=(struct ImportNode *)osAllocCleared(sizeof(struct ImportNode)))) { *seconderr=READCONFIG_NO_MEM; osClose(cfgfh); return(FALSE); } jbAddNode(&LastArea->TossNodes,(struct jbNode *)tmpinode); if(!(Parse4D(buf2,&tmpinode->Node))) { sprintf(cfgerr,"Invalid node number \"%s\"",buf2); osClose(cfgfh); return(FALSE); } } } else if(stricmp(cfgword,"BANNED")==0) { if(!LastArea) { strcpy(cfgerr,"No previous AREA line"); osClose(cfgfh); return(FALSE); } while(jbstrcpy(buf2,cfgbuf,100,&jbcpos)) { if(!(Parse4D(buf2,&tmp4d))) { sprintf(cfgerr,"Invalid node number \"%s\"",buf2); osClose(cfgfh); return(FALSE); } for(tmpnode=(struct ConfigNode *)cfg->CNodeList.First;tmpnode;tmpnode=tmpnode->Next) if(Compare4D(&tmp4d,&tmpnode->Node)==0) break; if(!tmpnode) { sprintf(cfgerr,"Unconfigured node \"%s\"",buf2); osClose(cfgfh); return(FALSE); } if(!(tmpbnode=(struct BannedNode *)osAllocCleared(sizeof(struct BannedNode)))) { *seconderr=READCONFIG_NO_MEM; osClose(cfgfh); return(FALSE); } jbAddNode(&LastArea->BannedNodes,(struct jbNode *)tmpbnode); tmpbnode->ConfigNode=tmpnode; } } else if(stricmp(cfgword,"DESCRIPTION")==0) { if(!LastArea) { strcpy(cfgerr,"No previous AREA line"); osClose(cfgfh); return(FALSE); } if(!(jbstrcpy(LastArea->Description,cfgbuf,80,&jbcpos))) { strcpy(cfgerr,"Missing argument"); osClose(cfgfh); return(FALSE); } } else if(stricmp(cfgword,"GROUP")==0) { if(!LastArea) { strcpy(cfgerr,"No previous AREA line"); osClose(cfgfh); return(FALSE); } if(!(jbstrcpy(buf2,cfgbuf,30,&jbcpos))) { strcpy(cfgerr,"Missing argument"); osClose(cfgfh); return(FALSE); } if(!CorrectFlags(buf2)) { sprintf(cfgerr,"Invalid group \"%s\"",buf2); osClose(cfgfh); return(FALSE); } LastArea->Group=buf2[0]; } else if(stricmp(cfgword,"KEEPNUM")==0) { if(!LastArea) { strcpy(cfgerr,"No previous AREA line"); osClose(cfgfh); return(FALSE); } if(!(jbstrcpy(buf2,cfgbuf,30,&jbcpos))) { strcpy(cfgerr,"Missing argument"); osClose(cfgfh); return(FALSE); } LastArea->KeepNum=atol(buf2); } else if(stricmp(cfgword,"KEEPDAYS")==0) { if(!LastArea) { strcpy(cfgerr,"No previous AREA line"); osClose(cfgfh); return(FALSE); } if(!(jbstrcpy(buf2,cfgbuf,30,&jbcpos))) { strcpy(cfgerr,"Missing argument"); osClose(cfgfh); return(FALSE); } LastArea->KeepDays=atol(buf2); } else if(stricmp(cfgword,"AREAFIXNAME")==0) { if(!(tmpareafixname=(struct AreaFixName *)osAllocCleared(sizeof(struct AreaFixName)))) { *seconderr=READCONFIG_NO_MEM; osClose(cfgfh); return(FALSE); } jbAddNode(&cfg->AreaFixList,(struct jbNode *)tmpareafixname); if(!(jbstrcpy(tmpareafixname->Name,cfgbuf,36,&jbcpos))) { strcpy(cfgerr,"Missing argument"); osClose(cfgfh); return(FALSE); } } else if(stricmp(cfgword,"FILEATTACH")==0) { while(jbstrcpy(buf2,cfgbuf,100,&jbcpos)) { if(!(tmppatternnode=(struct PatternNode *)osAllocCleared(sizeof(struct PatternNode)))) { *seconderr=READCONFIG_NO_MEM; osClose(cfgfh); return(FALSE); } if(!(Parse4DPat(buf2,&tmppatternnode->Pattern))) { sprintf(cfgerr,"Invalid node pattern \"%s\"",buf2); osClose(cfgfh); return(FALSE); } jbAddNode(&cfg->FileAttachList,(struct jbNode *)tmppatternnode); } } else if(stricmp(cfgword,"BOUNCE")==0) { while(jbstrcpy(buf2,cfgbuf,100,&jbcpos)) { if(!(tmppatternnode=(struct PatternNode *)osAllocCleared(sizeof(struct PatternNode)))) { *seconderr=READCONFIG_NO_MEM; osClose(cfgfh); return(FALSE); } if(!(Parse4DPat(buf2,&tmppatternnode->Pattern))) { sprintf(cfgerr,"Invalid node pattern \"%s\"",buf2); osClose(cfgfh); return(FALSE); } jbAddNode(&cfg->BounceList,(struct jbNode *)tmppatternnode); } } else if(stricmp(cfgword,"INBOUND")==0) { if(!(jbstrcpy(cfg->cfg_Inbound,cfgbuf,100,&jbcpos))) { strcpy(cfgerr,"Missing argument"); osClose(cfgfh); return(FALSE); } } else if(stricmp(cfgword,"OUTBOUND")==0) { if(!(jbstrcpy(cfg->cfg_Outbound,cfgbuf,100,&jbcpos))) { strcpy(cfgerr,"Missing argument"); osClose(cfgfh); return(FALSE); } } else if(stricmp(cfgword,"SYSOP")==0) { if(!(jbstrcpy(cfg->cfg_Sysop,cfgbuf,35,&jbcpos))) { strcpy(cfgerr,"Missing argument"); osClose(cfgfh); return(FALSE); } } else if(stricmp(cfgword,"BEFORETOSS")==0) { if(!(jbstrcpy(cfg->cfg_BeforeToss,cfgbuf,79,&jbcpos))) { strcpy(cfgerr,"Missing argument"); osClose(cfgfh); return(FALSE); } } else if(stricmp(cfgword,"BEFOREPACK")==0) { if(!(jbstrcpy(cfg->cfg_BeforePack,cfgbuf,79,&jbcpos))) { strcpy(cfgerr,"Missing argument"); osClose(cfgfh); return(FALSE); } } else if(stricmp(cfgword,"NODELIST")==0) { int i; if(!(jbstrcpy(cfg->cfg_Nodelist,cfgbuf,100,&jbcpos))) { strcpy(cfgerr,"Missing argument"); osClose(cfgfh); return(FALSE); } cfg->cfg_NodelistType=NULL; if(!(jbstrcpy(buf2,cfgbuf,40,&jbcpos))) { strcpy(cfgerr,"Missing argument"); osClose(cfgfh); return(FALSE); } for(i=0;AvailNodelists[i].name;i++) if(stricmp(buf2,AvailNodelists[i].name)==0) break; if(!AvailNodelists[i].name) { sprintf(cfgerr,"Unsupported nodelist type \"%s\"",buf2); osClose(cfgfh); return(FALSE); } cfg->cfg_NodelistType= &AvailNodelists[i]; } else if(stricmp(cfgword,"AREAFIXHELP")==0) { if(!(jbstrcpy(cfg->cfg_AreaFixHelp,cfgbuf,100,&jbcpos))) { strcpy(cfgerr,"Missing argument"); osClose(cfgfh); return(FALSE); } } else if(stricmp(cfgword,"LOGFILE")==0) { if(!(jbstrcpy(cfg->cfg_LogFile,cfgbuf,100,&jbcpos))) { strcpy(cfgerr,"Missing argument"); osClose(cfgfh); return(FALSE); } } else if(stricmp(cfgword,"LOGLEVEL")==0) { if(!(jbstrcpy(buf2,cfgbuf,100,&jbcpos))) { strcpy(cfgerr,"Missing argument"); osClose(cfgfh); return(FALSE); } if(atoi(buf2)<1 || atoi(buf2)>6) { strcpy(cfgerr,"Loglevel out of range"); osClose(cfgfh); return(FALSE); } cfg->cfg_LogLevel=atoi(buf2); } else if(stricmp(cfgword,"STATSFILE")==0) { if(!(jbstrcpy(cfg->cfg_StatsFile,cfgbuf,100,&jbcpos))) { strcpy(cfgerr,"Missing argument"); osClose(cfgfh); return(FALSE); } } else if(stricmp(cfgword,"DUPEFILE")==0) { if(!(jbstrcpy(cfg->cfg_DupeFile,cfgbuf,100,&jbcpos))) { strcpy(cfgerr,"Missing argument"); osClose(cfgfh); return(FALSE); } if(!(jbstrcpy(buf2,cfgbuf,200,&jbcpos))) { strcpy(cfgerr,"Missing argument"); osClose(cfgfh); return(FALSE); } cfg->cfg_DupeSize=atoi(buf2); } else if(stricmp(cfgword,"DUPEMODE")==0) { if(!(jbstrcpy(buf2,cfgbuf,200,&jbcpos))) { strcpy(cfgerr,"Missing argument"); osClose(cfgfh); return(FALSE); } if(stricmp(buf2,"IGNORE")==0) cfg->cfg_DupeMode=DUPE_IGNORE; else if(stricmp(buf2,"KILL")==0) cfg->cfg_DupeMode=DUPE_KILL; else if(stricmp(buf2,"BAD")==0) cfg->cfg_DupeMode=DUPE_BAD; else { sprintf(cfgerr,"Unknown dupemode \"%s\"",buf2); osClose(cfgfh); return(FALSE); } } else if(stricmp(cfgword,"LOOPMODE")==0) { if(!(jbstrcpy(buf2,cfgbuf,200,&jbcpos))) { strcpy(cfgerr,"Missing argument"); osClose(cfgfh); return(FALSE); } if(stricmp(buf2,"IGNORE")==0) cfg->cfg_LoopMode=LOOP_IGNORE; else if(stricmp(buf2,"LOG")==0) cfg->cfg_LoopMode=LOOP_LOG; else if(stricmp(buf2,"LOG+BAD")==0) cfg->cfg_LoopMode=LOOP_LOGBAD; else { sprintf(cfgerr,"Unknown loopmode \"%s\"",buf2); osClose(cfgfh); return(FALSE); } } else if(stricmp(cfgword,"TEMPDIR")==0) { if(!(jbstrcpy(cfg->cfg_TempDir,cfgbuf,100,&jbcpos))) { strcpy(cfgerr,"Missing argument"); osClose(cfgfh); return(FALSE); } } else if(stricmp(cfgword,"CREATEPKTDIR")==0) { if(!(jbstrcpy(cfg->cfg_PacketCreate,cfgbuf,100,&jbcpos))) { strcpy(cfgerr,"Missing argument"); osClose(cfgfh); return(FALSE); } } else if(stricmp(cfgword,"PACKETDIR")==0) { if(!(jbstrcpy(cfg->cfg_PacketDir,cfgbuf,100,&jbcpos))) { strcpy(cfgerr,"Missing argument"); osClose(cfgfh); return(FALSE); } } else if(stricmp(cfgword,"PACKER")==0) { if(!(tmppacker=(struct Packer *)osAllocCleared(sizeof(struct Packer)))) { *seconderr=READCONFIG_NO_MEM; osClose(cfgfh); return(FALSE); } jbAddNode(&cfg->PackerList,(struct jbNode *)tmppacker); LastPacker=tmppacker; if(!(jbstrcpy(LastPacker->Name,cfgbuf,10,&jbcpos))) { strcpy(cfgerr,"Missing argument"); osClose(cfgfh); return(FALSE); } if(!(jbstrcpy(LastPacker->Packer,cfgbuf,80,&jbcpos))) { strcpy(cfgerr,"Missing argument"); osClose(cfgfh); return(FALSE); } if(!(jbstrcpy(LastPacker->Unpacker,cfgbuf,80,&jbcpos))) { strcpy(cfgerr,"Missing argument"); osClose(cfgfh); return(FALSE); } if(!(jbstrcpy(LastPacker->Recog,cfgbuf,80,&jbcpos))) { strcpy(cfgerr,"Missing argument"); osClose(cfgfh); return(FALSE); } } else if(stricmp(cfgword,"ROUTE")==0) { if(!(tmproute=(struct Route *)osAllocCleared(sizeof(struct Route)))) { *seconderr=READCONFIG_NO_MEM; osClose(cfgfh); return(FALSE); } jbAddNode(&cfg->RouteList,(struct jbNode *)tmproute); /* Pattern */ if(!(jbstrcpy(buf2,cfgbuf,200,&jbcpos))) { strcpy(cfgerr,"Missing argument"); osClose(cfgfh); return(FALSE); } if(!(Parse4DPat(buf2,&tmproute->Pattern))) { sprintf(cfgerr,"Invalid node pattern \"%s\"",buf2); osClose(cfgfh); return(FALSE); } /* Dest */ if(!(jbstrcpy(buf2,cfgbuf,200,&jbcpos))) { strcpy(cfgerr,"Missing argument"); osClose(cfgfh); return(FALSE); } if(!(Parse4DDestPat(buf2,&tmproute->DestPat))) { sprintf(cfgerr,"Invalid node pattern \"%s\"",buf2); osClose(cfgfh); return(FALSE); } /* Aka */ if(!(jbstrcpy(buf2,cfgbuf,200,&jbcpos))) { strcpy(cfgerr,"Missing argument"); osClose(cfgfh); return(FALSE); } if(!(Parse4D(buf2,&tmp4d))) { sprintf(cfgerr,"Invalid node number \"%s\"",buf2); osClose(cfgfh); return(FALSE); } for(tmpaka=(struct Aka *)cfg->AkaList.First;tmpaka;tmpaka=tmpaka->Next) if(Compare4D(&tmp4d,&tmpaka->Node)==0) break; if(!tmpaka) { sprintf(cfgerr,"Unconfigured AKA \"%s\"",buf2); osClose(cfgfh); return(FALSE); } tmproute->Aka=tmpaka; } else if(stricmp(cfgword,"CHANGE")==0) { if(!(tmpchange=(struct Change *)osAllocCleared(sizeof(struct Change)))) { *seconderr=READCONFIG_NO_MEM; osClose(cfgfh); return(FALSE); } jbAddNode(&cfg->ChangeList,(struct jbNode *)tmpchange); /* Type pattern */ if(!(jbstrcpy(buf2,cfgbuf,200,&jbcpos))) { strcpy(cfgerr,"Missing argument"); osClose(cfgfh); return(FALSE); } if(buf2[0]=='*') { tmpchange->ChangeNormal=TRUE; tmpchange->ChangeCrash=TRUE; tmpchange->ChangeHold=TRUE; tmpchange->ChangeDirect=TRUE; } else { c=0; while(buf2[c]!=0) { d=c; while(buf2[d]!=',' && buf2[d]!=0) d++; if(buf2[d]==',') { buf2[d]=0; d++; } if(stricmp(&buf2[c],"NORMAL")==0) tmpchange->ChangeNormal=TRUE; else if(stricmp(&buf2[c],"CRASH")==0) tmpchange->ChangeCrash=TRUE; else if(stricmp(&buf2[c],"HOLD")==0) tmpchange->ChangeHold=TRUE; else if(stricmp(&buf2[c],"DIRECT")==0) tmpchange->ChangeDirect=TRUE; else { sprintf(cfgerr,"Unknown mail flavour \"%s\"",buf2); osClose(cfgfh); return(FALSE); } c=d; } } /* Node pattern */ if(!(jbstrcpy(buf2,cfgbuf,200,&jbcpos))) { strcpy(cfgerr,"Missing argument"); osClose(cfgfh); return(FALSE); } if(!(Parse4DPat(buf2,&tmpchange->Pattern))) { sprintf(cfgerr,"Invalid node pattern \"%s\"",buf2); osClose(cfgfh); return(FALSE); } /* New type */ if(!(jbstrcpy(buf2,cfgbuf,200,&jbcpos))) { strcpy(cfgerr,"Missing argument"); osClose(cfgfh); return(FALSE); } if(stricmp(buf2,"NORMAL")==0) tmpchange->DestPri=PKTS_NORMAL; else if(stricmp(buf2,"CRASH")==0) tmpchange->DestPri=PKTS_CRASH; else if(stricmp(buf2,"HOLD")==0) tmpchange->DestPri=PKTS_HOLD; else if(stricmp(buf2,"DIRECT")==0) tmpchange->DestPri=PKTS_DIRECT; else { sprintf(cfgerr,"Unknown mail flavour \"%s\"",buf2); osClose(cfgfh); return(FALSE); } } else if(stricmp(cfgword,"AREALIST")==0) { if(!(tmparealist=(struct Arealist *)osAllocCleared(sizeof(struct Arealist)))) { *seconderr=READCONFIG_NO_MEM; osClose(cfgfh); return(FALSE); } jbAddNode(&cfg->ArealistList,(struct jbNode *)tmparealist); if(!(jbstrcpy(buf2,cfgbuf,200,&jbcpos))) { strcpy(cfgerr,"Missing argument"); osClose(cfgfh); return(FALSE); } if(!(Parse4D(buf2,&tmp4d))) { sprintf(cfgerr,"Invalid node number \"%s\"",buf2); osClose(cfgfh); return(FALSE); } for(tmpnode=(struct ConfigNode *)cfg->CNodeList.First;tmpnode;tmpnode=tmpnode->Next) if(Compare4D(&tmp4d,&tmpnode->Node)==0) break; if(!tmpnode) { sprintf(cfgerr,"Unconfigured node \"%s\"",buf2); osClose(cfgfh); return(FALSE); } tmparealist->Node=tmpnode; if(!(jbstrcpy(tmparealist->AreaFile,cfgbuf,80,&jbcpos))) { strcpy(cfgerr,"Missing argument"); osClose(cfgfh); return(FALSE); } while(jbstrcpy(buf2,cfgbuf,200,&jbcpos)) { if(stricmp(buf2,"FORWARD")==0) { tmparealist->Flags|=AREALIST_FORWARD; } else if(stricmp(buf2,"DESC")==0) { tmparealist->Flags|=AREALIST_DESC; } else if(stricmp(buf2,"GROUP")==0) { if(!jbstrcpy(buf2,cfgbuf,200,&jbcpos)) { strcpy(cfgerr,"Missing argument"); osClose(cfgfh); return(FALSE); } if(!CorrectFlags(buf2)) { sprintf(cfgerr,"Invalid group \"%s\"",buf2); osClose(cfgfh); return(FALSE); } tmparealist->Group=buf2[0]; } else { sprintf(cfgerr,"Unknown switch \"%s\"",buf2); osClose(cfgfh); return(FALSE); } } } else if(stricmp(cfgword,"FILTER")==0) { if(!(tmpfilter=(struct Filter *)osAllocCleared(sizeof(struct Filter)))) { *seconderr=READCONFIG_NO_MEM; osClose(cfgfh); return(FALSE); } jbAddNode(&cfg->FilterList,(struct jbNode *)tmpfilter); jbNewList(&tmpfilter->CommandList); LastFilter=tmpfilter; if(!(jbstrcpyrest(tmpfilter->Filter,cfgbuf,400,&jbcpos))) { strcpy(cfgerr,"Missing argument"); osClose(cfgfh); return(FALSE); } } else if(stricmp(cfgword,"KILL")==0 || stricmp(cfgword,"TWIT")==0) { if(!LastFilter) { strcpy(cfgerr,"No previous FILTER line"); osClose(cfgfh); return(FALSE); } if(!(tmpcommand=(struct Command *)osAllocCleared(sizeof(struct Command)))) { *seconderr=READCONFIG_NO_MEM; osClose(cfgfh); return(FALSE); } jbAddNode(&LastFilter->CommandList,(struct jbNode *)tmpcommand); if(stricmp(cfgword,"KILL")==0) tmpcommand->Cmd=COMMAND_KILL; if(stricmp(cfgword,"TWIT")==0) tmpcommand->Cmd=COMMAND_TWIT; } else if(stricmp(cfgword,"COPY")==0 || stricmp(cfgword,"EXECUTE")==0 || stricmp(cfgword,"WRITELOG")==0 || stricmp(cfgword,"WRITEBAD")==0 || stricmp(cfgword,"BOUNCEMSG")==0 || stricmp(cfgword,"BOUNCEHEADER")==0) { if(!LastFilter) { strcpy(cfgerr,"No previous FILTER line"); osClose(cfgfh); return(FALSE); } if(!(tmpcommand=(struct Command *)osAllocCleared(sizeof(struct Command)))) { *seconderr=READCONFIG_NO_MEM; osClose(cfgfh); return(FALSE); } jbAddNode(&LastFilter->CommandList,(struct jbNode *)tmpcommand); if(stricmp(cfgword,"COPY")==0) tmpcommand->Cmd=COMMAND_COPY; if(stricmp(cfgword,"EXECUTE")==0) tmpcommand->Cmd=COMMAND_EXECUTE; if(stricmp(cfgword,"WRITELOG")==0) tmpcommand->Cmd=COMMAND_WRITELOG; if(stricmp(cfgword,"WRITEBAD")==0) tmpcommand->Cmd=COMMAND_WRITEBAD; if(stricmp(cfgword,"BOUNCEMSG")==0) tmpcommand->Cmd=COMMAND_BOUNCEMSG; if(stricmp(cfgword,"BOUNCEHEADER")==0) tmpcommand->Cmd=COMMAND_BOUNCEHEADER; if(!(jbstrcpy(buf2,cfgbuf,200,&jbcpos))) { strcpy(cfgerr,"Missing argument"); osClose(cfgfh); return(FALSE); } if(!(tmpcommand->string=(uchar *)osAlloc(strlen(buf2)+1))) { *seconderr=READCONFIG_NO_MEM; osClose(cfgfh); return(FALSE); } strcpy(tmpcommand->string,buf2); } else if(stricmp(cfgword,"REMAPMSG")==0) { if(!LastFilter) { strcpy(cfgerr,"No previous FILTER line"); osClose(cfgfh); return(FALSE); } if(!(tmpcommand=(struct Command *)osAllocCleared(sizeof(struct Command)))) { *seconderr=READCONFIG_NO_MEM; osClose(cfgfh); return(FALSE); } jbAddNode(&LastFilter->CommandList,(struct jbNode *)tmpcommand); tmpcommand->Cmd=COMMAND_REMAPMSG; if(!(jbstrcpy(buf2,cfgbuf,200,&jbcpos))) { strcpy(cfgerr,"Missing argument"); osClose(cfgfh); return(FALSE); } if(!(tmpcommand->string=(uchar *)osAlloc(strlen(buf2)+1))) { *seconderr=READCONFIG_NO_MEM; osClose(cfgfh); return(FALSE); } strcpy(tmpcommand->string,buf2); if(!(jbstrcpy(buf2,cfgbuf,200,&jbcpos))) { strcpy(cfgerr,"Missing argument"); osClose(cfgfh); return(FALSE); } if(!(Parse4DDestPat(buf2,&tmpcommand->n4ddestpat))) { sprintf(cfgerr,"Invalid node pattern \"%s\"",buf2); osClose(cfgfh); return(FALSE); } } else if(stricmp(cfgword,"REMOTEAF")==0) { if(!LastCNode) { strcpy(cfgerr,"No previous NODE line"); osClose(cfgfh); return(FALSE); } if(!(jbstrcpy(LastCNode->RemoteAFName,cfgbuf,36,&jbcpos))) { strcpy(cfgerr,"Missing argument"); osClose(cfgfh); return(FALSE); } if(!(jbstrcpy(LastCNode->RemoteAFPw,cfgbuf,72,&jbcpos))) { strcpy(cfgerr,"Missing argument"); osClose(cfgfh); return(FALSE); } while(jbstrcpy(buf2,cfgbuf,200,&jbcpos)) { if(stricmp(buf2,"NEEDSPLUS")==0) LastCNode->Flags|=NODE_AFNEEDSPLUS; else { sprintf(cfgerr,"Unknown switch \"%s\"",buf2); osClose(cfgfh); return(FALSE); } } } else if(stricmp(cfgword,"REMOTESYSOP")==0) { if(!LastCNode) { strcpy(cfgerr,"No previous NODE line"); osClose(cfgfh); return(FALSE); } if(!(jbstrcpy(LastCNode->SysopName,cfgbuf,36,&jbcpos))) { strcpy(cfgerr,"Missing argument"); osClose(cfgfh); return(FALSE); } } else if(stricmp(cfgword,"STRIPRE")==0) { cfg->cfg_Flags|=CFG_STRIPRE; } else if(stricmp(cfgword,"FORCEINTL")==0) { cfg->cfg_Flags|=CFG_FORCEINTL; } else if(stricmp(cfgword,"BOUNCEHEADERONLY")==0) { cfg->cfg_Flags|=CFG_BOUNCEHEADERONLY; } else if(stricmp(cfgword,"REMOVEWHENFEED")==0) { cfg->cfg_Flags|=CFG_REMOVEWHENFEED; } else if(stricmp(cfgword,"INCLUDEFORWARD")==0) { cfg->cfg_Flags|=CFG_INCLUDEFORWARD; } else if(stricmp(cfgword,"NOMAXOUTBOUNDZONE")==0) { cfg->cfg_Flags|=CFG_NOMAXOUTBOUNDZONE; } else if(stricmp(cfgword,"ALLOWKILLSENT")==0) { cfg->cfg_Flags|=CFG_ALLOWKILLSENT; } else if(stricmp(cfgword,"FLOWCRLF")==0) { cfg->cfg_Flags|=CFG_FLOWCRLF; } else if(stricmp(cfgword,"NOEXPORTNETMAIL")==0) { cfg->cfg_Flags|=CFG_NOEXPORTNETMAIL; } else if(stricmp(cfgword,"NOROUTE")==0) { cfg->cfg_Flags|=CFG_NOROUTE; } else if(stricmp(cfgword,"ANSWERRECEIPT")==0) { cfg->cfg_Flags|=CFG_ANSWERRECEIPT; } else if(stricmp(cfgword,"ANSWERAUDIT")==0) { cfg->cfg_Flags|=CFG_ANSWERAUDIT; } else if(stricmp(cfgword,"CHECKSEENBY")==0) { cfg->cfg_Flags|=CFG_CHECKSEENBY; } else if(stricmp(cfgword,"CHECKPKTDEST")==0) { cfg->cfg_Flags|=CFG_CHECKPKTDEST; } else if(stricmp(cfgword,"PATH3D")==0) { cfg->cfg_Flags|=CFG_PATH3D; } else if(stricmp(cfgword,"IMPORTEMPTYNETMAIL")==0) { cfg->cfg_Flags|=CFG_IMPORTEMPTYNETMAIL; } else if(stricmp(cfgword,"IMPORTAREAFIX")==0) { cfg->cfg_Flags|=CFG_IMPORTAREAFIX; } else if(stricmp(cfgword,"AREAFIXREMOVE")==0) { cfg->cfg_Flags|=CFG_AREAFIXREMOVE; } else if(stricmp(cfgword,"NODIRECTATTACH")==0) { cfg->cfg_Flags|=CFG_NODIRECTATTACH; } else if(stricmp(cfgword,"BOUNCEPOINTS")==0) { cfg->cfg_Flags|=CFG_BOUNCEPOINTS; } else if(stricmp(cfgword,"IMPORTSEENBY")==0) { cfg->cfg_Flags|=CFG_IMPORTSEENBY; } else if(stricmp(cfgword,"WEEKDAYNAMING")==0) { cfg->cfg_Flags|=CFG_WEEKDAYNAMING; } else if(stricmp(cfgword,"ADDTID")==0) { cfg->cfg_Flags|=CFG_ADDTID; } else if(stricmp(cfgword,"ALLOWRESCAN")==0) { cfg->cfg_Flags|=CFG_ALLOWRESCAN; } else if(stricmp(cfgword,"FORWARDPASSTHRU")==0) { cfg->cfg_Flags|=CFG_FORWARDPASSTHRU; } else if(stricmp(cfgword,"MAXPKTSIZE")==0) { if(!(jbstrcpy(buf2,cfgbuf,200,&jbcpos))) { strcpy(cfgerr,"Missing argument"); osClose(cfgfh); return(FALSE); } cfg->cfg_MaxPktSize=atoi(buf2)*1024; } else if(stricmp(cfgword,"MAXBUNDLESIZE")==0) { if(!(jbstrcpy(buf2,cfgbuf,200,&jbcpos))) { strcpy(cfgerr,"Missing argument"); osClose(cfgfh); return(FALSE); } cfg->cfg_MaxBundleSize=atoi(buf2)*1024; } else if(stricmp(cfgword,"DEFAULTZONE")==0) { if(!(jbstrcpy(buf2,cfgbuf,200,&jbcpos))) { strcpy(cfgerr,"Missing argument"); osClose(cfgfh); return(FALSE); } cfg->cfg_DefaultZone=atoi(buf2); } else if(stricmp(cfgword,"AREAFIXMAXLINES")==0) { if(!(jbstrcpy(buf2,cfgbuf,200,&jbcpos))) { strcpy(cfgerr,"Missing argument"); osClose(cfgfh); return(FALSE); } cfg->cfg_AreaFixMaxLines=atoi(buf2); } /*************************** MSG ******************************/ #ifdef MSGBASE_MSG else if(stricmp(cfgword,"MSG_HIGHWATER")==0) { cfg->cfg_msg_Flags|=CFG_MSG_HIGHWATER; } else if(stricmp(cfgword,"MSG_WRITEBACK")==0) { cfg->cfg_msg_Flags|=CFG_MSG_WRITEBACK; } #endif /*************************** JAM ******************************/ #ifdef MSGBASE_JAM else if(stricmp(cfgword,"JAM_HIGHWATER")==0) { cfg->cfg_jam_Flags|=CFG_JAM_HIGHWATER; } else if(stricmp(cfgword,"JAM_LINK")==0) { cfg->cfg_jam_Flags|=CFG_JAM_LINK; } else if(stricmp(cfgword,"JAM_QUICKLINK")==0) { cfg->cfg_jam_Flags|=CFG_JAM_QUICKLINK; } else if(stricmp(cfgword,"JAM_MAXOPEN")==0) { if(!(jbstrcpy(buf2,cfgbuf,200,&jbcpos))) { strcpy(cfgerr,"Missing argument"); osClose(cfgfh); return(FALSE); } cfg->cfg_jam_MaxOpen=atoi(buf2); } #endif /*************************** Unknown *****************************/ else if(cfgword[0]!=0 && cfgword[0]!=';') { sprintf(cfgerr,"Unknown keyword \"%s\"",cfgword); osClose(cfgfh); return(FALSE); } } osClose(cfgfh); return(TRUE); } bool CheckConfig(struct Config *cfg,uchar *cfgerr) { struct Area *a1,*a2; struct PatternNode *patternnode; struct Route *route; struct Change *change; struct Filter *filter; struct Command *command; uchar buf[50]; if(cfg->cfg_TempDir[0]==0) strcpy(cfg->cfg_TempDir,cfg->cfg_Inbound); if(cfg->cfg_PacketCreate[0]==0) strcpy(cfg->cfg_PacketCreate,cfg->cfg_Outbound); if(cfg->cfg_PacketDir[0]==0) strcpy(cfg->cfg_PacketDir,cfg->cfg_Outbound); if(!cfg->AkaList.First) { sprintf(cfgerr,"No AKAs configured"); return(FALSE); } if(!cfg->cfg_NodelistType) { /* Check if any pattern needs a nodelist */ for(patternnode=(struct PatternNode *)cfg->FileAttachList.First;patternnode;patternnode=patternnode->Next) if(!Check4DPatNodelist(&patternnode->Pattern)) { Print4DPat(&patternnode->Pattern,buf); sprintf(cfgerr,"Nodelist needed for pattern \"%s\"",buf); return(FALSE); } for(patternnode=(struct PatternNode *)cfg->BounceList.First;patternnode;patternnode=patternnode->Next) if(!Check4DPatNodelist(&patternnode->Pattern)) { Print4DPat(&patternnode->Pattern,buf); sprintf(cfgerr,"Nodelist needed for pattern \"%s\"",buf); return(FALSE); } for(route=(struct Route *)cfg->RouteList.First;route;route=route->Next) { if(!Check4DPatNodelist(&route->Pattern)) { Print4DPat(&route->Pattern,buf); sprintf(cfgerr,"Nodelist needed for pattern \"%s\"",buf); return(FALSE); } if(!Check4DPatNodelist(&route->DestPat)) { Print4DDestPat(&route->DestPat,buf); sprintf(cfgerr,"Nodelist needed for pattern \"%s\"",buf); return(FALSE); } } for(change=(struct Change *)cfg->ChangeList.First;change;change=change->Next) if(!Check4DPatNodelist(&change->Pattern)) { Print4DPat(&change->Pattern,buf); sprintf(cfgerr,"Nodelist needed for pattern \"%s\"",buf); return(FALSE); } } /* Check for areas with same path */ for(a1=(struct Area *)cfg->AreaList.First;a1;a1=a1->Next) { if(a1->AreaType != AREATYPE_DEFAULT && a1->Messagebase) { for(a2=a1->Next;a2;a2=a2->Next) if(a2->Messagebase && stricmp(a1->Path,a2->Path)==0) { sprintf(cfgerr,"The areas %s and %s both have the same path",a1->Tagname,a2->Tagname); return(FALSE); } } } for(filter=(struct Filter *)cfg->FilterList.First;filter;filter=filter->Next) { if(!CheckFilter(filter->Filter,cfgerr)) return(FALSE); for(command=(struct Command *)filter->CommandList.First;command;command=command->Next) { if(command->Cmd == COMMAND_COPY) { for(a1=(struct Area *)config.AreaList.First;a1;a1=a1->Next) if(stricmp(a1->Tagname,command->string)==0) break; if(!a1) { sprintf(cfgerr,"Filter: Area %s for COPY command not found",command->string); return(FALSE); } if(a1->AreaType != AREATYPE_LOCAL) { sprintf(cfgerr,"Filter: Area %s for COPY command is not a local area",command->string); return(FALSE); } } if(command->Cmd == COMMAND_REMAPMSG) { if(!cfg->cfg_NodelistType && !Check4DPatNodelist(&command->n4ddestpat)) { Print4DDestPat(&command->n4ddestpat,buf); sprintf(cfgerr,"Filter: Nodelist needed for pattern \"%s\"",buf); return(FALSE); } } } } return(TRUE); } void InitConfig(struct Config *cfg) { memset(cfg,0,sizeof(struct Config)); strcpy(cfg->cfg_Sysop,"Sysop"); cfg->cfg_LogLevel=3; cfg->cfg_DupeSize=10000; cfg->cfg_DefaultZone=2; jbNewList(&cfg->AkaList); jbNewList(&cfg->AreaList); jbNewList(&cfg->CNodeList); jbNewList(&cfg->PackerList); jbNewList(&cfg->RouteList); jbNewList(&cfg->FileAttachList); jbNewList(&cfg->BounceList); jbNewList(&cfg->ChangeList); jbNewList(&cfg->AreaFixList); jbNewList(&cfg->ArealistList); jbNewList(&cfg->FilterList); } void WriteSafely(osFile fh,uchar *str) { uchar buf[300]; ushort c,d; d=0; for(c=0;str[c];c++) { if(str[c]=='"' || str[c]=='\\') buf[d++]='\\'; buf[d++]=str[c]; } buf[d]=0; osFPrintf(fh,"\"%s\"",buf); } void WriteNode4D(osFile fh,struct Node4D *n4d) { osFPrintf(fh,"%lu:%lu/%lu.%lu",n4d->Zone,n4d->Net,n4d->Node,n4d->Point); } uchar *nodekeywords[]={"DEFAULTGROUP","REMOTESYSOP","REMOTEAF", "AREAFIXINFO","NODE","PKTFROM",NULL}; uchar *areakeywords[]={"IGNORESEENBY","IGNOREDUPES","DEFREADONLY", "MANDATORY","UNCONFIRMED","KEEPNUM","KEEPDAYS", "GROUP","DESCRIPTION","BANNED","EXPORT","IMPORT", "AREA","NETMAIL",NULL}; void WriteNode(struct ConfigNode *tmpnode,osFile osfh) { osFPrintf(osfh,"NODE "); WriteNode4D(osfh,&tmpnode->Node); osFPrintf(osfh," "); if(tmpnode->Packer) WriteSafely(osfh,tmpnode->Packer->Name); else WriteSafely(osfh,""); osFPrintf(osfh," "); WriteSafely(osfh,tmpnode->PacketPW); if(tmpnode->Flags & NODE_PASSIVE) osFPrintf(osfh," PASSIVE"); if(tmpnode->Flags & NODE_NOTIFY) osFPrintf(osfh," NOTIFY"); if(tmpnode->Flags & NODE_NOSEENBY) osFPrintf(osfh," NOSEENBY"); if(tmpnode->Flags & NODE_TINYSEENBY) osFPrintf(osfh," TINYSEENBY"); if(tmpnode->Flags & NODE_FORWARDREQ) osFPrintf(osfh," FORWARDREQ"); if(tmpnode->Flags & NODE_PACKNETMAIL) osFPrintf(osfh," PACKNETMAIL"); if(tmpnode->Flags & NODE_SENDAREAFIX) osFPrintf(osfh," SENDAREAFIX"); if(tmpnode->Flags & NODE_SENDTEXT) osFPrintf(osfh," SENDTEXT"); if(tmpnode->Flags & NODE_AUTOADD) osFPrintf(osfh," AUTOADD"); if(tmpnode->EchomailPri == PKTS_CRASH) osFPrintf(osfh," CRASH"); if(tmpnode->EchomailPri == PKTS_DIRECT) osFPrintf(osfh," DIRECT"); if(tmpnode->EchomailPri == PKTS_HOLD) osFPrintf(osfh," HOLD"); osFPrintf(osfh,"\n"); if(tmpnode->Flags & NODE_PKTFROM) { osFPrintf(osfh,"PKTFROM "); WriteNode4D(osfh,&tmpnode->PktFrom); osFPrintf(osfh,"\n"); } if(tmpnode->AreafixPW[0] || tmpnode->Groups[0] || tmpnode->ReadOnlyGroups[0] || tmpnode->AddGroups[0]) { osFPrintf(osfh,"AREAFIXINFO "); WriteSafely(osfh,tmpnode->AreafixPW); osFPrintf(osfh," "); WriteSafely(osfh,tmpnode->Groups); osFPrintf(osfh," "); WriteSafely(osfh,tmpnode->ReadOnlyGroups); osFPrintf(osfh," "); WriteSafely(osfh,tmpnode->AddGroups); osFPrintf(osfh," "); osFPrintf(osfh,"\n"); } if(tmpnode->RemoteAFName[0]) { osFPrintf(osfh,"REMOTEAF "); WriteSafely(osfh,tmpnode->RemoteAFName); osFPrintf(osfh," "); WriteSafely(osfh,tmpnode->RemoteAFPw); if(tmpnode->Flags & NODE_AFNEEDSPLUS) osFPrintf(osfh," NEEDSPLUS"); osFPrintf(osfh,"\n"); } if(tmpnode->SysopName[0]) { osFPrintf(osfh,"REMOTESYSOP "); WriteSafely(osfh,tmpnode->SysopName); osFPrintf(osfh,"\n"); } if(tmpnode->DefaultGroup) osFPrintf(osfh,"DEFAULTGROUP %lc\n",tmpnode->DefaultGroup); } void WriteArea(struct Area *tmparea,osFile osfh) { struct ImportNode *tmpinode; struct TossNode *tmptnode; struct BannedNode *tmpbnode; ulong c; if(tmparea->AreaType == AREATYPE_NETMAIL) osFPrintf(osfh,"NETMAIL "); if(tmparea->AreaType == AREATYPE_LOCAL) osFPrintf(osfh,"LOCALAREA "); else osFPrintf(osfh,"AREA "); WriteSafely(osfh,tmparea->Tagname); osFPrintf(osfh," "); WriteNode4D(osfh,&tmparea->Aka->Node); if(tmparea->Messagebase) { osFPrintf(osfh," %s ",tmparea->Messagebase->name); WriteSafely(osfh,tmparea->Path); osFPrintf(osfh,"\n"); } else { osFPrintf(osfh,"\n"); } if(tmparea->AreaType == AREATYPE_NETMAIL) { c=0; for(tmpinode=(struct ImportNode *)tmparea->TossNodes.First;tmpinode;tmpinode=tmpinode->Next) { if(c%10==0) { if(c!=0) osFPrintf(osfh,"\n"); osFPrintf(osfh,"IMPORT"); } osFPrintf(osfh," "); WriteNode4D(osfh,&tmpinode->Node); c++; } if(c!=0) osFPrintf(osfh,"\n"); } else if(tmparea->AreaType == AREATYPE_ECHOMAIL || tmparea->AreaType == AREATYPE_DEFAULT) { c=0; for(tmptnode=(struct TossNode *)tmparea->TossNodes.First;tmptnode;tmptnode=tmptnode->Next) { if(c%10==0) { if(c!=0) osFPrintf(osfh,"\n"); osFPrintf(osfh,"EXPORT"); } osFPrintf(osfh," "); if(tmptnode->Flags & TOSSNODE_READONLY) osFPrintf(osfh,"!"); if(tmptnode->Flags & TOSSNODE_WRITEONLY) osFPrintf(osfh,"@"); if(tmptnode->Flags & TOSSNODE_FEED) osFPrintf(osfh,"%%"); WriteNode4D(osfh,&tmptnode->ConfigNode->Node); c++; } if(c!=0) osFPrintf(osfh,"\n"); } c=0; for(tmpbnode=(struct BannedNode *)tmparea->BannedNodes.First;tmpbnode;tmpbnode=tmpbnode->Next) { if(c%10==0) { if(c!=0) osFPrintf(osfh,"\n"); osFPrintf(osfh,"BANNED"); } osFPrintf(osfh," "); WriteNode4D(osfh,&tmpbnode->ConfigNode->Node); c++; } if(c!=0) osFPrintf(osfh,"\n"); if(tmparea->Description[0]!=0) { osFPrintf(osfh,"DESCRIPTION "); WriteSafely(osfh,tmparea->Description); osFPrintf(osfh,"\n"); } if(tmparea->Group) osFPrintf(osfh,"GROUP %lc\n",tmparea->Group); if(tmparea->KeepNum) osFPrintf(osfh,"KEEPNUM %lu\n",tmparea->KeepNum); if(tmparea->KeepDays) osFPrintf(osfh,"KEEPDAYS %lu\n",tmparea->KeepDays); if(tmparea->Flags & AREA_UNCONFIRMED) osFPrintf(osfh,"UNCONFIRMED\n"); if(tmparea->Flags & AREA_MANDATORY) osFPrintf(osfh,"MANDATORY\n"); if(tmparea->Flags & AREA_DEFREADONLY) osFPrintf(osfh,"DEFREADONLY\n"); if(tmparea->Flags & AREA_IGNOREDUPES) osFPrintf(osfh,"IGNOREDUPES\n"); if(tmparea->Flags & AREA_IGNORESEENBY) osFPrintf(osfh,"IGNORESEENBY\n"); } bool UpdateConfig(struct Config *cfg,uchar *cfgerr) { uchar cfgtemp[110],cfgbak[110]; uchar cfgword[30],buf[100]; osFile oldfh,newfh; bool skiparea,skipnode,dontwrite,copyres; struct ConfigNode *cnode; struct Area *area; struct Node4D n4d; ulong jbcpos,c; strcpy(cfgtemp,cfg->filename); strcat(cfgtemp,".tmp"); strcpy(cfgbak,cfg->filename); strcat(cfgbak,".bak"); if(!(oldfh=osOpen(cfg->filename,MODE_OLDFILE))) { ulong err=osError(); sprintf(cfgerr,"Unable to read file %s (error: %s)",cfg->filename,osErrorMsg(err)); return(FALSE); } if(!(newfh=osOpen(cfgtemp,MODE_NEWFILE))) { ulong err=osError(); sprintf(cfgerr,"Unable to write to config file %s (error: %s)",cfgtemp,osErrorMsg(err)); osClose(oldfh); return(FALSE); } skiparea=FALSE; skipnode=FALSE; while(osFGets(oldfh,cfgbuf,4000)) { jbcpos=0; copyres=jbstrcpy(cfgword,cfgbuf,30,&jbcpos); if(stricmp(cfgword,"AREA")==0 || stricmp(cfgword,"NETMAIL")==0 || stricmp(cfgword,"LOCALAREA")==0) { skiparea=FALSE; if(jbstrcpy(buf,cfgbuf,100,&jbcpos)) { for(area=(struct Area *)cfg->AreaList.First;area;area=area->Next) if(stricmp(buf,area->Tagname)==0) break; /* Area has been changed */ if(area && area->changed) { skiparea=TRUE; WriteArea(area,newfh); osFPrintf(newfh,"\n"); area->changed=FALSE; } /* Area has been removed */ if(!area) { skiparea=TRUE; } } } if(stricmp(cfgword,"NODE")==0) { skipnode=FALSE; if(jbstrcpy(buf,cfgbuf,100,&jbcpos)) { if(Parse4D(buf,&n4d)) { for(cnode=(struct ConfigNode *)cfg->CNodeList.First;cnode;cnode=cnode->Next) if(Compare4D(&n4d,&cnode->Node)==0) break; if(cnode && cnode->changed) { skipnode=TRUE; WriteNode(cnode,newfh); osFPrintf(newfh,"\n"); cnode->changed=FALSE; } } } } dontwrite=FALSE; if(skiparea) { for(c=0;areakeywords[c];c++) if(stricmp(cfgword,areakeywords[c])==0) dontwrite=TRUE; if(!copyres) dontwrite=TRUE; /* Skip empty lines */ } if(skipnode) { for(c=0;nodekeywords[c];c++) if(stricmp(cfgword,nodekeywords[c])==0) dontwrite=TRUE; if(!copyres) dontwrite=TRUE; /* Skip empty lines */ } if(!dontwrite) osPuts(newfh,cfgbuf); } for(area=(struct Area *)cfg->AreaList.First;area;area=area->Next) if(area->changed) { osFPrintf(newfh,"\n"); WriteArea(area,newfh); area->changed=FALSE; } osClose(oldfh); osClose(newfh); osDelete(cfgbak); osRename(cfg->filename,cfgbak); osRename(cfgtemp,cfg->filename); cfg->changed=FALSE; return(TRUE); } void FreeConfig(struct Config *cfg) { struct Area *area; struct Aka *aka; struct ConfigNode *cnode; struct Filter *filter; struct Command *command; /* Config */ for(area=(struct Area *)cfg->AreaList.First;area;area=area->Next) { jbFreeList(&area->TossNodes); jbFreeList(&area->BannedNodes); } for(aka=(struct Aka *)cfg->AkaList.First;aka;aka=aka->Next) { jbFreeList(&aka->AddList); jbFreeList(&aka->RemList); } for(cnode=(struct ConfigNode *)cfg->CNodeList.First;cnode;cnode=cnode->Next) jbFreeList(&cnode->RemoteAFList); for(filter=(struct Filter *)cfg->FilterList.First;filter;filter=filter->Next) { for(command=(struct Command *)filter->CommandList.First;command;command=command->Next) if(command->string) osFree(command->string); jbFreeList(&filter->CommandList); } jbFreeList(&cfg->AkaList); jbFreeList(&cfg->AreaList); jbFreeList(&cfg->CNodeList); jbFreeList(&cfg->PackerList); jbFreeList(&cfg->RouteList); jbFreeList(&cfg->RouteList); jbFreeList(&cfg->FileAttachList); jbFreeList(&cfg->BounceList); jbFreeList(&cfg->ChangeList); jbFreeList(&cfg->AreaFixList); jbFreeList(&cfg->ArealistList); jbFreeList(&cfg->FilterList); } crashmail-0.71/src/crashmail/config.h0100644000000000000000000001725307763451635016303 0ustar rootroot#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; uchar Flags; uchar AreaType; uchar Tagname[80]; uchar Description[80]; struct Messagebase *Messagebase; uchar Path[80]; uchar Group; struct jbList TossNodes; struct jbList BannedNodes; /* Maint */ ulong KeepNum,KeepDays; /* Stats */ ulong Texts; ulong NewTexts; ulong Dupes; ulong NewDupes; ushort Last8Days[8]; time_t FirstTime; time_t LastTime; /* Other */ bool scanned; }; struct Aka { struct Aka *Next; struct Node4D Node; uchar 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; ushort 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; uchar Command[80]; }; struct ConfigNode { struct ConfigNode *Next; bool changed; struct Node4D Node; uchar PacketPW[9]; struct Packer *Packer; bool IsInSeenBy; uchar AreafixPW[40]; uchar Groups[30]; uchar ReadOnlyGroups[30]; uchar AddGroups[30]; uchar DefaultGroup; ulong Flags; uchar SysopName[36]; uchar EchomailPri; struct Node4D PktFrom; uchar RemoteAFName[36]; uchar RemoteAFPw[72]; struct jbList RemoteAFList; uchar LastArcName[12]; /* Stats */ ulong GotNetmails; ulong GotNetmailBytes; ulong SentNetmails; ulong SentNetmailBytes; ulong GotEchomails; ulong GotEchomailBytes; ulong SentEchomails; ulong SentEchomailBytes; ulong Dupes; time_t FirstTime; }; struct Packer { struct Packer *Next; uchar Name[10]; uchar Packer[80]; uchar Unpacker[80]; uchar 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; uchar DestPri; }; struct AreaFixName { struct AreaFixName *Next; uchar Name[36]; }; #define AREALIST_DESC 1 #define AREALIST_FORWARD 2 struct Arealist { struct Arealist *Next; struct ConfigNode *Node; uchar AreaFile[80]; ushort Flags; uchar 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; ushort Cmd; uchar *string; struct Node4D n4d; struct Node4DPat n4ddestpat; }; struct Filter { struct Filter *Next; uchar 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; uchar filename[100]; uchar cfg_Sysop[36]; uchar cfg_Inbound[100]; uchar cfg_Outbound[100]; uchar cfg_TempDir[100]; uchar cfg_PacketCreate[100]; uchar cfg_PacketDir[100]; uchar cfg_LogFile[100]; uchar cfg_StatsFile[100]; uchar cfg_DupeFile[100]; uchar cfg_BeforeToss[80]; uchar cfg_BeforePack[80]; ulong cfg_LogLevel; ulong cfg_DupeSize; ulong cfg_MaxPktSize; ulong cfg_MaxBundleSize; uchar cfg_AreaFixHelp[100]; uchar cfg_Nodelist[100]; struct Nodelist *cfg_NodelistType; ulong cfg_AreaFixMaxLines; uchar cfg_GroupNames[30][80]; ulong cfg_Flags; ushort cfg_DupeMode; ushort cfg_LoopMode; ulong 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 ulong cfg_amiga_LogBufferLines; ulong cfg_amiga_LogBufferSecs; ulong cfg_amiga_Flags; #endif #ifdef MSGBASE_UMS uchar cfg_ums_RFCGatewayName[40]; struct Node4D cfg_ums_RFCGatewayNode; uchar cfg_ums_LoginName[80]; uchar cfg_ums_LoginPassword[80]; uchar cfg_ums_LoginServer[80]; uchar cfg_ums_GatewayName[36]; ulong cfg_ums_Flags; #endif #ifdef MSGBASE_MSG ulong cfg_msg_Flags; #endif #ifdef MSGBASE_JAM ulong cfg_jam_MaxOpen; ulong cfg_jam_Flags; #endif }; bool ReadConfig(uchar *filename,struct Config *cfg,short *seconderr,ulong *cfgline,uchar *cfgerr); bool UpdateConfig(struct Config *cfg,uchar *cfgerr); void InitConfig(struct Config *cfg); void FreeConfig(struct Config *cfg); bool CheckConfig(struct Config *cfg,uchar *cfgerr); /* Should not be called in prefs */ #endif crashmail-0.71/src/crashmail/dupe.c0100644000000000000000000002115407762203623015750 0ustar rootroot#include "crashmail.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 }; ulong calcstringcrc(uchar *str) { ulong 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 { ulong offset; ulong crc32; }; bool dupechanged; struct dupeentry *dupebuf; ulong dupeentrynum,dupeentrymax; osFile dupefh; void adddupeindex(ulong offset,ulong crc32) { dupebuf[dupeentrynum].offset=offset; dupebuf[dupeentrynum].crc32=crc32; dupeentrynum++; if(dupeentrynum > dupeentrymax) dupeentrymax=dupeentrynum; if(dupeentrynum == config.cfg_DupeSize) dupeentrynum=0; } void copydupe(ushort c,osFile oldfh,osFile newfh) { uchar buf[300]; ushort size; osSeek(oldfh,dupebuf[c].offset,OFFSET_BEGINNING); if(osRead(oldfh,&size,sizeof(ushort))!=sizeof(ushort)) return; if(osRead(oldfh,buf,size) != size) return; if(!osWrite(newfh,&size,sizeof(ushort))) { ulong 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)) { ulong err=osError(); LogWrite(1,SYSTEMERR,"Failed to write to temporary dupe file"); LogWrite(1,SYSTEMERR,"Error: %s",osErrorMsg(err)); return; } } bool OpenDupeDB(void) { uchar buf[300]; ulong offset,crc32,*crc32p; ushort 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))) { ulong err=osError(); LogWrite(1,SYSTEMERR,"Failed to open dupe file %s in read/write mode",config.cfg_DupeFile); LogWrite(1,SYSTEMERR,"Error: %s",config.cfg_DupeFile,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(ushort))==sizeof(ushort)) { 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,(ulong)size) != size) { LogWrite(1,SYSTEMERR,"Error in dupe file %s, exiting...",config.cfg_DupeFile); osClose(dupefh); return(FALSE); } crc32p=(ulong *)buf; crc32=*crc32p; adddupeindex(offset,crc32); offset += size+2; } dupechanged=FALSE; return(TRUE); } void CloseDupeDB(void) { osFile newfh; ulong c; uchar duptemp[200]; if(!dupechanged) { osClose(dupefh); return; } strcpy(duptemp,config.cfg_DupeFile); strcat(duptemp,".tmp"); if(!(newfh=osOpen(duptemp,MODE_NEWFILE))) { ulong 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;cMSGID[0] == 0) return(FALSE); /* No dupechecking for messages without MSGID */ crc32=calcstringcrc(mm->MSGID); crc32p=(ulong *)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;cDate > (*(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; ulong 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(uchar *file) { int c; uchar 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(uchar *file) { if(strlen(file)!=12) return(FALSE); if(file[8]!='.') return(FALSE); if(stricmp(&file[9],"pkt")!=0) return(FALSE); return(TRUE); } bool IsNewPkt(uchar *file) { if(strlen(file) < 7) return(FALSE); if(stricmp(&file[strlen(file)-7],".newpkt")!=0) return(FALSE); return(TRUE); } bool IsPktTmp(uchar *file) { if(strlen(file) < 7) return(FALSE); if(stricmp(&file[strlen(file)-7],".pkttmp")!=0) return(FALSE); return(TRUE); } bool IsOrphan(uchar *file) { if(strlen(file) < 7) return(FALSE); if(stricmp(&file[strlen(file)-7],".orphan")!=0) return(FALSE); return(TRUE); } bool IsBad(uchar *file) { if(strlen(file)>4 && stricmp(&file[strlen(file)-4],".bad")==0) return(TRUE); return(FALSE); } void striptrail(uchar *str) { int c; for(c=strlen(str)-1;str[c] < 33 && c>=0;c--) str[c]=0; } void striplead(uchar *str) { int c; c=0; while(str[c]==' ') c++; strcpy(str,&str[c]); } void stripleadtrail(uchar *str) { striplead(str); striptrail(str); } void BadFile(uchar *filename,uchar *comment) { uchar destname[100],numbuf[10]; ulong 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,",%ld",num); strcat(destname,numbuf); } num++; } while(osExists(destname)); if(!movefile(filename,destname)) { ulong 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(uchar group,uchar *node) { uchar c; for(c=0;ctm_mday, monthnames[tp->tm_mon], tp->tm_year % 100, tp->tm_hour, tp->tm_min, tp->tm_sec); } #define COPYBUFSIZE 5000 bool copyfile(uchar *file,uchar *newfile) { osFile ifh,ofh; ulong len; uchar *copybuf; if(!(copybuf=(uchar *)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(uchar *file,uchar *newfile) { if(osRename(file,newfile)) return(TRUE); /* rename was enough */ if(!copyfile(file,newfile)) return(FALSE); osDelete(file); return(TRUE); } uchar ChangeType(struct Node4D *dest,uchar pri) { struct Change *change; uchar 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) { uchar 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(uchar *date) { ulong 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(uchar *buf, struct Node4D *n4d, uchar *domain) { ulong c=0; uchar buf2[100]; domain[0]=0; mystrncpy(buf2,buf,100); for(c=0;c0 && 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(uchar *dest,uchar *nam,struct Node4D *node,uchar *dom) { uchar 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,uchar *name,bool rfcaddr) { osFile fh; uchar *domain; struct Aka *aka; struct TextChunk *tmp; ulong c,d,lastspace; uchar 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))) { ulong 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(cLength) { for(d=c;dLength && 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(dLength) { lastspace=0; c=0; while(tmp->Data[d+c]==10) d++; while(c<78 && d+cLength && 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,uchar *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))) { ulong 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) { uchar *sbbuf; if(!(sbbuf=mmMakeSeenByBuf(&mm->SeenBy))) { osClose(fh); return(FALSE); } if(sbbuf[0]) { if(!osWrite(fh,sbbuf,(ulong)strlen(sbbuf))) { ioerror=TRUE; ioerrornum=osError(); } } osFree(sbbuf); } /* Write path */ for(path=(struct Path *)mm->Path.First;path;path=path->Next) for(c=0;cPaths;c++) if(path->Path[c][0]!=0) { if(!osWrite(fh,"\x01PATH: ",7)) { ioerror=TRUE; ioerrornum=osError(); } if(!osWrite(fh,path->Path[c],(ulong)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); } crashmail-0.71/src/crashmail/misc.h0100644000000000000000000000235307763164102015752 0ustar rootrootvoid ExpandPacker(uchar *cmd,uchar *dest,ulong destsize,uchar *archive,uchar *file); bool SortFEList(struct jbList *list); void BadFile(uchar *filename,uchar *comment); bool IsArc(uchar *file); bool IsPkt(uchar *file); bool IsNewPkt(uchar *file); bool IsPktTmp(uchar *file); bool IsOrphan(uchar *file); bool IsBad(uchar *file); void striptrail(uchar *str); void striplead(uchar *str); void stripleadtrail(uchar *str); bool MatchFlags(uchar group,uchar *node); void ExpandFilter(uchar *cmd,uchar *dest,ulong destsize, uchar *rfc1, uchar *rfc2, uchar *msg, uchar *area, uchar *subj, uchar *time, uchar *from, uchar *to, uchar *orignode, uchar *destnode); void MakeFidoDate(time_t tim,uchar *dest); bool AddTID(struct MemMessage *mm); bool movefile(uchar *file,uchar *newfile); bool copyfile(uchar *file,uchar *newfile); uchar ChangeType(struct Node4D *dest,uchar pri); bool MakeNetmailKludges(struct MemMessage *mm); time_t FidoToTime(uchar *date); bool Parse5D(uchar *buf, struct Node4D *n4d, uchar *domain); bool ExtractAddress(uchar *origin, struct Node4D *n4d); unsigned long hextodec(char *hex); bool WriteMSG(struct MemMessage *mm,uchar *file); bool WriteRFC(struct MemMessage *mm,uchar *name,bool rfcaddr); crashmail-0.71/src/crashmail/areafix.c0100644000000000000000000013634507764162573016455 0ustar rootroot#include "crashmail.h" void SendRemoteAreafix(void); struct Arealist *FindForward(uchar *tagname,uchar *flags); void RemoteAreafixAdd(uchar *area,struct ConfigNode *node); void RemoteAreafixRemove(uchar *area,struct ConfigNode *node); bool CheckFlags(uchar group,uchar *node); struct afReply { struct MemMessage *mm; uchar subject[72]; ulong lines; ulong part; }; struct afReply *afInitReply(uchar *fromname,struct Node4D *from4d,uchar *toname,struct Node4D *to4d,uchar *subject); void afFreeReply(struct afReply *af); void afAddLine(struct afReply *af,uchar *fmt,...); void afSendMessage(struct afReply *af); void AddCommandReply(struct afReply *af,uchar *cmd,uchar *reply); void rawSendList(short type,struct Node4D *from4d,uchar *toname,struct ConfigNode *cnode); void rawSendHelp(struct Node4D *from4d,uchar *toname,struct ConfigNode *cnode); void rawSendInfo(struct Node4D *from4d,uchar *toname,struct ConfigNode *cnode); void SendRemoveMessages(struct Area *area); void RemoveDeletedAreas(void); #define COMMAND_UPDATE 1 #define COMMAND_ADD 2 #define COMMAND_REMOVE 3 bool AreaFix(struct MemMessage *mm) { struct Arealist *arealist; struct ConfigNode *cnode; struct Area *area; struct TossNode *temptnode; struct BannedNode *bannednode; struct TextChunk *chunk; ulong c,d,q,jbcpos; uchar password[100],buf[100],buf2[100]; bool stop,sendareaquery,sendarealist,sendareaunlinked,sendhelp,sendinfo,done,iswild; bool globalrescan,wasfeed; uchar *opt,areaname[100],command; struct Route *tmproute; struct afReply *afr; Print4D(&mm->OrigNode,buf); LogWrite(4,AREAFIX,"AreaFix: Request from %s",buf); /* Init reply structure */ for(tmproute=(struct Route *)config.RouteList.First;tmproute;tmproute=tmproute->Next) if(Compare4DPat(&tmproute->Pattern,&mm->OrigNode)==0) break; if(!tmproute) { Print4D(&mm->OrigNode,buf); LogWrite(1,TOSSINGERR,"No route found for %s",buf); return(TRUE); } if(!(afr=afInitReply(config.cfg_Sysop,&tmproute->Aka->Node,mm->From,&mm->OrigNode,"AreaFix response"))) return(FALSE); for(cnode=(struct ConfigNode *)config.CNodeList.First;cnode;cnode=cnode->Next) if(Compare4D(&cnode->Node,&mm->OrigNode)==0) break; if(!cnode) { Print4D(&mm->OrigNode,buf); LogWrite(2,AREAFIX,"AreaFix: Unknown node %s",buf); afAddLine(afr,"Sorry, your node is not configured here."); afSendMessage(afr); afFreeReply(afr); return(TRUE); } jbcpos=0; jbstrcpy(password,mm->Subject,100,&jbcpos); if(stricmp(password,cnode->AreafixPW)!=0) { Print4D(&mm->OrigNode,buf); LogWrite(2,AREAFIX,"AreaFix: Wrong password \"%s\" from %s",password,buf); afAddLine(afr,"Sorry, wrong password."); afSendMessage(afr); afFreeReply(afr); return(TRUE); } sendarealist=FALSE; sendareaquery=FALSE; sendareaunlinked=FALSE; sendinfo=FALSE; sendhelp=FALSE; globalrescan=FALSE; done=FALSE; if(jbstrcpy(password,mm->Subject,100,&jbcpos)) { if(stricmp(password,"-q")==0 || stricmp(password,"-l")==0) { done=TRUE; sendarealist=TRUE; AddCommandReply(afr,password,"Sending list of all areas"); } } stop=FALSE; for(chunk=(struct TextChunk *)mm->TextChunks.First;chunk && !stop && !ctrlc;chunk=chunk->Next) { for(c=0;cLength && !stop && !ctrlc;c++) { for(d=0;d<100 && chunk->Data[c+d]!=13 && chunk->Data[c+d]!=10 && c+dLength;d++) buf[d]=chunk->Data[c+d]; buf[d]=0; c+=d; if(strncmp(buf,"---",3)==0) stop=TRUE; stripleadtrail(buf); if(buf[0]=='%') { jbcpos=0; jbstrcpy(buf2,buf,100,&jbcpos); if(stricmp(buf2,"%PAUSE")==0) { if(cnode->Flags & NODE_PASSIVE) { AddCommandReply(afr,buf,"Your system is already passive"); } else { cnode->Flags|=NODE_PASSIVE; cnode->changed=TRUE; config.changed=TRUE; done=TRUE; AddCommandReply(afr,buf,"Your system is marked as passive"); AddCommandReply(afr,"","Send %%RESUME to get echomail again"); } } else if(stricmp(buf2,"%RESUME")==0) { if(cnode->Flags & NODE_PASSIVE) { cnode->Flags&=~NODE_PASSIVE; cnode->changed=TRUE; config.changed=TRUE; done=TRUE; AddCommandReply(afr,buf,"Your system is active again"); } else { AddCommandReply(afr,buf,"Your system is not paused"); } } else if(stricmp(buf2,"%PWD")==0) { if(jbstrcpy(buf2,buf,40,&jbcpos)) { strcpy(cnode->AreafixPW,buf2); cnode->changed=TRUE; config.changed=TRUE; done=TRUE; AddCommandReply(afr,buf,"AreaFix password changed"); } else { AddCommandReply(afr,buf,"No new password specified"); } } else if(stricmp(buf2,"%RESCAN")==0) { if(config.cfg_Flags & CFG_ALLOWRESCAN) { AddCommandReply(afr,buf,"Will rescan all areas added after this line"); globalrescan=TRUE; } else { AddCommandReply(afr,buf,"No rescanning allowed"); } } else if(stricmp(buf2,"%COMPRESS")==0) { if(jbstrcpy(buf2,buf,40,&jbcpos)) { bool gotpacker; struct Packer *tmppacker; gotpacker=FALSE; tmppacker=NULL; if(buf2[0]!='?') { if(stricmp(buf2,"NONE")==0) { tmppacker=NULL; gotpacker=TRUE; } else { for(tmppacker=(struct Packer *)config.PackerList.First;tmppacker;tmppacker=tmppacker->Next) if(stricmp(buf2,tmppacker->Name)==0 && tmppacker->Packer[0]) break; if(tmppacker) gotpacker=TRUE; else AddCommandReply(afr,buf,"Unknown packer. Choose from this list:"); } } else { AddCommandReply(afr,buf,"Sending list of packers:"); } if(gotpacker) { cnode->Packer=tmppacker; cnode->changed=TRUE; config.changed=TRUE; AddCommandReply(afr,buf,"Packed changed"); } else { for(tmppacker=(struct Packer *)config.PackerList.First;tmppacker;tmppacker=tmppacker->Next) { if(tmppacker->Packer[0]) AddCommandReply(afr,"",tmppacker->Name); } AddCommandReply(afr,"","NONE"); } done=TRUE; } else { AddCommandReply(afr,buf,"No new method specified"); } } else if(stricmp(buf2,"%LIST")==0) { sendarealist=TRUE; done=TRUE; AddCommandReply(afr,buf,"Sending list of all areas"); } else if(stricmp(buf2,"%QUERY")==0) { sendareaquery=TRUE; done=TRUE; AddCommandReply(afr,buf,"Sending query"); } else if(stricmp(buf2,"%UNLINKED")==0) { sendareaunlinked=TRUE; done=TRUE; AddCommandReply(afr,buf,"Sending list of all unlinkedareas"); } else if(stricmp(buf2,"%HELP")==0) { sendhelp=TRUE; done=TRUE; AddCommandReply(afr,buf,"Sending help file"); } else if(stricmp(buf2,"%INFO")==0) { sendinfo=TRUE; done=TRUE; AddCommandReply(afr,buf,"Sending configuration info"); } else { done=TRUE; AddCommandReply(afr,buf,"Unknown command"); } } else if(buf[0]!=1 && buf[0]!=0) { ulong rescannum; bool patterndone,dorescan,areaexists,success; struct Area *rescanarea; done=TRUE; rescannum=0; dorescan=FALSE; /* Separate command, name and opt */ mystrncpy(areaname,buf,100); opt=""; for(q=0;areaname[q];q++) if(areaname[q]==',') opt=&areaname[q]; if(opt[0]==',') { opt[0]=0; opt=&opt[1]; while(opt[0]==32) opt=&opt[1]; } striptrail(areaname); striptrail(opt); if(areaname[0]=='-') { command=COMMAND_REMOVE; strcpy(areaname,&areaname[1]); } else if(areaname[0]=='=') { command=COMMAND_UPDATE; strcpy(areaname,&areaname[1]); } else { command=COMMAND_ADD; if(areaname[0]=='+') strcpy(areaname,&areaname[1]); } if(!osCheckPattern(areaname)) { afAddLine(afr,"%-30.30s Invalid pattern",buf); } else { iswild=osIsPattern(areaname); if(iswild) { afAddLine(afr,"%s",buf); afAddLine(afr,""); } patterndone=FALSE; areaexists=FALSE; rescanarea=NULL; for(area=(struct Area *)config.AreaList.First;area && !ctrlc;area=area->Next) if(area->AreaType == AREATYPE_ECHOMAIL) { if(osMatchPattern(areaname,area->Tagname)) { areaexists=TRUE; for(temptnode=(struct TossNode *)area->TossNodes.First;temptnode;temptnode=temptnode->Next) if(temptnode->ConfigNode == cnode) break; switch(command) { case COMMAND_ADD: if(!temptnode) { /* Do we have access? */ if(CheckFlags(area->Group,cnode->Groups) || CheckFlags(area->Group,cnode->ReadOnlyGroups)) { patterndone=TRUE; for(bannednode=(struct BannedNode *)area->BannedNodes.First;bannednode;bannednode=bannednode->Next) if(bannednode->ConfigNode == cnode) break; /* Are we banned? */ if(bannednode) { if(iswild) afAddLine(afr," You have been banned from %s",area->Tagname); else AddCommandReply(afr,buf,"You have been banned from that area"); LogWrite(3,AREAFIX,"AreaFix: This node is banned in %s",area->Tagname); } else { if((area->Flags & AREA_DEFREADONLY) || CheckFlags(area->Group,cnode->ReadOnlyGroups)) { LogWrite(4,AREAFIX,"AreaFix: Attached to %s as read-only",area->Tagname); if(iswild) afAddLine(afr," Attached to %s as read-only",area->Tagname); else AddCommandReply(afr,buf,"Attached as read-only"); } else { LogWrite(4,AREAFIX,"AreaFix: Attached to %s",area->Tagname); if(iswild) afAddLine(afr," Attached to %s",area->Tagname); else AddCommandReply(afr,buf,"Attached"); } if(!(temptnode=osAllocCleared(sizeof(struct TossNode)))) { afFreeReply(afr); nomem=TRUE; return(FALSE); } temptnode->ConfigNode=cnode; if((area->Flags & AREA_DEFREADONLY) || CheckFlags(area->Group,cnode->ReadOnlyGroups)) temptnode->Flags=TOSSNODE_READONLY; jbAddNode(&area->TossNodes,(struct jbNode *)temptnode); rescanarea=area; area->changed=TRUE; config.changed=TRUE; } } else if(!iswild) { AddCommandReply(afr,buf,"You don't have access to that area"); } } else { patterndone=TRUE; if(iswild) afAddLine(afr," You are already attached to %s",area->Tagname); else AddCommandReply(afr,buf,"You are already attached to that area"); } break; case COMMAND_REMOVE: if(!temptnode) { if(!iswild) { AddCommandReply(afr,buf,"You are not attached to that area"); patterndone=TRUE; } } else { patterndone=TRUE; if((area->Flags & AREA_MANDATORY) && !(temptnode->Flags & TOSSNODE_FEED)) { if(iswild) afAddLine(afr," You are not allowed to detach from %s",area->Tagname); else AddCommandReply(afr,buf,"You are not allowed to detach from that area"); } else { LogWrite(4,AREAFIX,"AreaFix: Detached from %s",area->Tagname); if(iswild) afAddLine(afr," Detached from %s",area->Tagname); else AddCommandReply(afr,buf,"Detached"); wasfeed=FALSE; if(temptnode->Flags & TOSSNODE_FEED) wasfeed=TRUE; jbFreeNode(&area->TossNodes,(struct jbNode *)temptnode); area->changed=TRUE; config.changed=TRUE; if(wasfeed && (config.cfg_Flags & CFG_REMOVEWHENFEED)) { LogWrite(2,AREAFIX,"AreaFix: Feed disconnected, removing area %s",area->Tagname); SendRemoveMessages(area); area->AreaType=AREATYPE_DELETED; } else if(config.cfg_Flags & CFG_AREAFIXREMOVE) { if(area->TossNodes.First == NULL || (((struct TossNode*)area->TossNodes.First)->Next==NULL && ((struct TossNode*)area->TossNodes.First)->Flags & TOSSNODE_FEED)) { if(!area->Messagebase) { if(area->TossNodes.First) { LogWrite(3,AREAFIX,"AreaFix: Area %s removed, message sent to areafix",area->Tagname); RemoteAreafixRemove(area->Tagname,((struct TossNode*)area->TossNodes.First)->ConfigNode); } else { LogWrite(3,AREAFIX,"AreaFix: Area %s removed",area->Tagname); } area->AreaType=AREATYPE_DELETED; } } } } } break; case COMMAND_UPDATE: if(temptnode) { patterndone=TRUE; if(iswild) { afAddLine(afr," Nothing to do with %s",area->Tagname); } else { AddCommandReply(afr,buf,"Will rescan area"); rescanarea=area; } } break; } } } if(command==COMMAND_UPDATE || command==COMMAND_ADD) { if(!iswild && patterndone && rescanarea) { if(strnicmp(opt,"r=",2)==0) { rescannum=atoi(&opt[2]); dorescan=TRUE; } else if(opt[0]) { afAddLine(afr,"%-30.30s Unknown option %s","",opt); } if(globalrescan || dorescan) { if(config.cfg_Flags & CFG_ALLOWRESCAN) { if(!rescanarea->Messagebase) { afAddLine(afr,"%-30.30s Can't rescan, area is pass-through",""); } else if(!rescanarea->Messagebase->rescanfunc) { afAddLine(afr,"%-30.30s Can't rescan, messagebase does not support rescan",""); } else { LogWrite(4,AREAFIX,"AreaFix: Rescanning %s",rescanarea->Tagname); RescanNode=cnode; rescan_total=0; success=(*rescanarea->Messagebase->rescanfunc)(rescanarea,rescannum,HandleRescan); RescanNode=NULL; if(!success) { afFreeReply(afr); return(FALSE); } LogWrite(4,AREAFIX,"AreaFix: Rescanned %lu messages",rescan_total); afAddLine(afr,"%-30.30s Rescanned %lu messages","",rescan_total); } } else { afAddLine(afr,"%-30.30s No rescanning allowed",""); } } } } switch(command) { case COMMAND_ADD: if(!patterndone) { if(iswild) { afAddLine(afr," There were no matching areas to connect to"); } else { if(!areaexists) { if(cnode->Flags & NODE_FORWARDREQ) { arealist=FindForward(areaname,cnode->Groups); if(arealist) { uchar buf2[100]; LogWrite(3,AREAFIX,"AreaFix: %s requested from %lu:%lu/%lu.%lu",areaname,arealist->Node->Node.Zone,arealist->Node->Node.Net,arealist->Node->Node.Node,arealist->Node->Node.Point); sprintf(buf2,"Request sent to %u:%u/%u.%u",arealist->Node->Node.Zone,arealist->Node->Node.Net,arealist->Node->Node.Node,arealist->Node->Node.Point); AddCommandReply(afr,buf,buf2); RemoteAreafixAdd(areaname,arealist->Node); area=AddArea(areaname,&arealist->Node->Node,&tmproute->Aka->Node,TRUE,config.cfg_Flags & CFG_FORWARDPASSTHRU); area->Group=arealist->Group; if(area) { ushort flags; flags=0; if(CheckFlags(area->Group,cnode->ReadOnlyGroups)) flags|=TOSSNODE_READONLY; AddTossNode(area,cnode,flags); config.changed=TRUE; area->changed=TRUE; areaexists=TRUE; } } } } if(!areaexists) { AddCommandReply(afr,buf,"Unknown area"); LogWrite(3,AREAFIX,"AreaFix: Unknown area %s",areaname); } } } break; case COMMAND_REMOVE: if(!patterndone) { if(iswild) afAddLine(afr," There were no matching areas to detach from"); else AddCommandReply(afr,buf,"Unknown area"); } break; case COMMAND_UPDATE: if(!patterndone) { if(iswild) afAddLine(afr," There were no matching areas"); else AddCommandReply(afr,buf,"You are not attached to this area"); } else { if(rescanarea && !globalrescan && opt[0]==0) AddCommandReply(afr,buf,"Nothing to do"); } break; } if(iswild) afAddLine(afr,""); } } RemoveDeletedAreas(); } } if(done==FALSE) afAddLine(afr,"Nothing to do."); if(nomem || ioerror || ctrlc) { afFreeReply(afr); return(FALSE); } afSendMessage(afr); afFreeReply(afr); if(sendarealist) rawSendList(SENDLIST_FULL,&tmproute->Aka->Node,mm->From,cnode); if(sendareaquery) rawSendList(SENDLIST_QUERY,&tmproute->Aka->Node,mm->From,cnode); if(sendareaunlinked) rawSendList(SENDLIST_UNLINKED,&tmproute->Aka->Node,mm->From,cnode); if(sendhelp) rawSendHelp(&tmproute->Aka->Node,mm->From,cnode); if(sendinfo) rawSendInfo(&tmproute->Aka->Node,mm->From,cnode); /* Restore old MemMessage */ SendRemoteAreafix(); return(TRUE); } void SendRemoveMessages(struct Area *area) { struct TossNode *tn; uchar buf[100]; struct MemMessage *mm; for(tn=(struct TossNode *)area->TossNodes.First;tn;tn=tn->Next) { if(tn->ConfigNode->Flags & NODE_SENDAREAFIX) { LogWrite(5,AREAFIX,"AreaFix: Sending message to AreaFix at %ld:%ld/%ld.%ld", tn->ConfigNode->Node.Zone, tn->ConfigNode->Node.Net, tn->ConfigNode->Node.Node, tn->ConfigNode->Node.Point); if(!(mm=mmAlloc())) { nomem=TRUE; return; } Copy4D(&mm->DestNode,&tn->ConfigNode->Node); Copy4D(&mm->OrigNode,&area->Aka->Node); strcpy(mm->From,config.cfg_Sysop); strcpy(mm->To,tn->ConfigNode->RemoteAFName); strcpy(mm->Subject,tn->ConfigNode->RemoteAFPw); mm->Attr = FLAG_PVT; MakeFidoDate(time(NULL),mm->DateTime); mm->Flags |= MMFLAG_AUTOGEN; MakeNetmailKludges(mm); if(config.cfg_Flags & CFG_ADDTID) AddTID(mm); sprintf(buf,"-%s\x0d",area->Tagname); mmAddLine(mm,buf); sprintf(buf,"---\x0dGenerated by CrashMail "VERSION"\x0d"); mmAddLine(mm,buf); HandleMessage(mm); mmFree(mm); } if((tn->ConfigNode->Flags & NODE_SENDTEXT) && !(tn->Flags & TOSSNODE_FEED)) { LogWrite(5,AREAFIX,"AreaFix: Notifying sysop at %ld:%ld/%ld.%ld", tn->ConfigNode->Node.Zone, tn->ConfigNode->Node.Net, tn->ConfigNode->Node.Node, tn->ConfigNode->Node.Point); if(!(mm=mmAlloc())) return; Copy4D(&mm->DestNode,&tn->ConfigNode->Node); Copy4D(&mm->OrigNode,&area->Aka->Node); strcpy(mm->From,config.cfg_Sysop); strcpy(mm->To,tn->ConfigNode->SysopName); strcpy(mm->Subject,"Area removed"); mm->Attr = FLAG_PVT; MakeFidoDate(time(NULL),mm->DateTime); mm->Flags |= MMFLAG_AUTOGEN; MakeNetmailKludges(mm); if(config.cfg_Flags & CFG_ADDTID) AddTID(mm); sprintf(buf,"The area \"%s\" has been removed by the uplink.\x0d",area->Tagname); mmAddLine(mm,buf); if(tn->ConfigNode->Flags & NODE_SENDAREAFIX) { sprintf(buf,"A message has been sent to your AreaFix.\x0d"); mmAddLine(mm,buf); } HandleMessage(mm); mmFree(mm); } } } void RemoveDeletedAreas(void) { struct Area *area,*temparea; area=(struct Area *)config.AreaList.First; while(area) { temparea=area->Next; if(area->AreaType == AREATYPE_DELETED) { jbFreeList(&area->TossNodes); jbFreeNode(&config.AreaList,(struct jbNode *)area); config.changed=TRUE; } area=temparea; } } struct StatsNode { struct StatsNode *Next; uchar *Tagname; uchar *Desc; uchar Group; bool Attached; bool Feed; ulong WeekKB; /* -1 means unknown */ }; struct jbList SortList; bool AddSortList(uchar *tagname,uchar *desc,uchar group,bool attached,bool feed,long weekkb) { uchar *mtagname,*mdesc; struct StatsNode *ss; mtagname=(uchar *)osAlloc(strlen(tagname)+1); mdesc=(uchar *)osAlloc(strlen(desc)+1); ss=(struct StatsNode *)osAlloc(sizeof(struct StatsNode)); if(!mtagname || !mdesc || !ss) { if(mtagname) osFree(mtagname); if(mdesc) osFree(mdesc); if(ss) osFree(ss); return(FALSE); } strcpy(mtagname,tagname); strcpy(mdesc,desc); ss->Tagname=mtagname; ss->Desc=mdesc; ss->Group=group; ss->Attached=attached; ss->Feed=feed; ss->WeekKB=weekkb; jbAddNode(&SortList,(struct jbNode *)ss); return(TRUE); } void FreeSortList(void) { struct StatsNode *ss; for(ss=(struct StatsNode *)SortList.First;ss;ss=ss->Next) { if(ss->Tagname) osFree(ss->Tagname); if(ss->Desc) osFree(ss->Desc); } jbFreeList(&SortList); } int CompareAreas(const void *a1,const void *a2) { struct StatsNode **s1,**s2; s1=(struct StatsNode **)a1; s2=(struct StatsNode **)a2; if((*s1)->Group < (*s2)->Group) return(-1); if((*s1)->Group > (*s2)->Group) return(1); return(stricmp((*s1)->Tagname,(*s2)->Tagname)); } void SortSortList(void) { ulong nc; struct StatsNode *ss,**buf,**work; nc=0; for(ss=(struct StatsNode *)SortList.First;ss;ss=ss->Next) nc++; if(nc==0) return; if(!(buf=(struct StatsNode **)osAlloc(nc*sizeof(struct StatsNode *)))) { nomem=TRUE; return; } work=buf; for(ss=(struct StatsNode *)SortList.First;ss;ss=ss->Next) *work++=ss; qsort(buf,nc,4,CompareAreas); jbNewList(&SortList); for(work=buf;nc--;) jbAddNode(&SortList,(struct jbNode *)*work++); osFree(buf); } long CalculateWeekKB(struct Area *area) { if(area->FirstTime == 0 || DayStatsWritten == 0) { return(-1); } else { int days,c; unsigned long sum; days=DayStatsWritten-area->FirstTime / (24*60*60); if(days > 7) days=7; sum=0; for(c=1;cLast8Days[c]; if(sum == 0 && area->Texts!=0) { days=DayStatsWritten-area->FirstTime / (24*60*60); if(days==0) days=1; return(area->Texts/days); } else { if(days == 0) days=1; return(sum/days); } } } bool AddForwardList(struct Arealist *arealist) { bool res; osFile fh; uchar buf[200]; uchar desc[100]; ulong c,d; struct Area *area; struct StatsNode *ss; if(!(fh=osOpen(arealist->AreaFile,MODE_OLDFILE))) { ulong err=osError(); LogWrite(1,SYSTEMERR,"AreaFix: File %s not found",arealist->AreaFile); LogWrite(1,SYSTEMERR,"AreaFix: Error: %s",osErrorMsg(err)); return(TRUE); } while(osFGets(fh,buf,199)) { desc[0]=0; for(c=0;buf[c]>32;c++); if(buf[c]!=0) { buf[c]=0; c++; while(buf[c]<=32 && buf[c]!=0) c++; if(buf[c]!=0) { d=0; while(buf[c]!=0 && buf[c]!=10 && buf[c]!=13 && d<77) desc[d++]=buf[c++]; desc[d]=0; } } if(buf[0]!=0) { /* Don't add areas that exist locally */ for(area=(struct Area *)config.AreaList.First;area;area=area->Next) if(stricmp(buf,area->Tagname)==0) break; for(ss=(struct StatsNode *)SortList.First;ss;ss=ss->Next) if(stricmp(buf,ss->Tagname)==0) break; if(!area && !ss) { if(arealist->Flags & AREALIST_DESC) res=AddSortList(buf,desc,arealist->Group,FALSE,FALSE,-1); else res=AddSortList(buf,"",arealist->Group,FALSE,FALSE,-1); if(!res) { osClose(fh); return(FALSE); } } } } osClose(fh); return(TRUE); } void AddCommandReply(struct afReply *afr,uchar *cmd,uchar *reply) { if(strlen(cmd) <= 30) { afAddLine(afr,"%-30s %s",cmd,reply); } else { afAddLine(afr,"%s",cmd); afAddLine(afr,"%-30s %s","",reply); } } void rawSendList(short type,struct Node4D *from4d,uchar *toname,struct ConfigNode *cnode) { uchar buf[50]; struct TossNode *tn; struct Area *area; struct StatsNode *ss,*lastss; struct Arealist *arealist; short sendlisttotal,sendlistlinked; uchar ast; struct afReply *afr; /* Log action */ switch(type) { case SENDLIST_QUERY: LogWrite(4,AREAFIX,"AreaFix: Sending query to %lu:%lu/%lu.%lu", cnode->Node.Zone, cnode->Node.Net, cnode->Node.Node, cnode->Node.Point); break; case SENDLIST_UNLINKED: LogWrite(4,AREAFIX,"AreaFix: Sending list of unlinked areas to %lu:%lu/%lu.%lu", cnode->Node.Zone, cnode->Node.Net, cnode->Node.Node, cnode->Node.Point); break; case SENDLIST_FULL: LogWrite(4,AREAFIX,"AreaFix: Sending list of areas to %lu:%lu/%lu.%lu", cnode->Node.Zone, cnode->Node.Net, cnode->Node.Node, cnode->Node.Point); break; } /* Start building reply message */ if(!(afr=afInitReply(config.cfg_Sysop,from4d,toname,&cnode->Node,"AreaFix list of areas"))) return; switch(type) { case SENDLIST_QUERY: afAddLine(afr,"This is a list of all connected areas at %lu:%lu/%lu.%lu:", from4d->Zone, from4d->Net, from4d->Node, from4d->Point); break; case SENDLIST_FULL: afAddLine(afr,"This is a list of all available areas at %lu:%lu/%lu.%lu:", from4d->Zone, from4d->Net, from4d->Node, from4d->Point); break; case SENDLIST_UNLINKED: afAddLine(afr,"This is a list of all unlinked areas at %lu:%lu/%lu.%lu:", from4d->Zone, from4d->Net, from4d->Node, from4d->Point); break; } afAddLine(afr,""); /* Init list */ jbNewList(&SortList); /* Add local areas */ for(area=(struct Area *)config.AreaList.First;area;area=area->Next) if(area->AreaType == AREATYPE_ECHOMAIL) { short add; bool attached,feed; for(tn=(struct TossNode *)area->TossNodes.First;tn;tn=tn->Next) if(tn->ConfigNode == cnode) break; add=FALSE; switch(type) { case SENDLIST_QUERY: if(tn) add=TRUE; break; case SENDLIST_UNLINKED: if(!tn && (CheckFlags(area->Group,cnode->Groups) || CheckFlags(area->Group,cnode->ReadOnlyGroups))) add=TRUE; break; case SENDLIST_FULL: if(tn || (CheckFlags(area->Group,cnode->Groups) || CheckFlags(area->Group,cnode->ReadOnlyGroups))) add=TRUE; break; } if(add) { attached=FALSE; feed=FALSE; if(tn) attached=TRUE; if(tn && tn->Flags & TOSSNODE_FEED) feed=TRUE; if(!AddSortList(area->Tagname,area->Description,area->Group,attached,feed,CalculateWeekKB(area))) { LogWrite(1,SYSTEMERR,"AreaFix: Out of memory when building list of areas"); afAddLine(afr,"Failed to build list of areas, out of memory"); afSendMessage(afr); afFreeReply(afr); FreeSortList(); return; } } } /* Add forward-requestable areas */ if(config.cfg_Flags & CFG_INCLUDEFORWARD && (type == SENDLIST_UNLINKED || type == SENDLIST_FULL) && cnode->Flags & NODE_FORWARDREQ) { for(arealist=(struct Arealist *)config.ArealistList.First;arealist;arealist=arealist->Next) if((arealist->Flags & AREALIST_FORWARD) && CheckFlags(arealist->Group,cnode->Groups)) { if(!AddForwardList(arealist)) { LogWrite(1,SYSTEMERR,"AreaFix: Out of memory when building list of areas"); afAddLine(afr,"Failed to build list of areas, out of memory"); afSendMessage(afr); afFreeReply(afr); FreeSortList(); return; } } } /* Generate list */ SortSortList(); lastss=NULL; sendlisttotal=0; sendlistlinked=0; for(ss=(struct StatsNode *)SortList.First;ss;ss=ss->Next) { if(!lastss || lastss->Group!=ss->Group) { if(lastss) afAddLine(afr,""); if(ss->Group) afAddLine(afr," Group: %s",config.cfg_GroupNames[ss->Group-'A']); else afAddLine(afr," Group: %s",""); afAddLine(afr,""); afAddLine(afr," Tagname Description KB/week"); afAddLine(afr," ---------------------------- --------------------------------- -------"); } ast=' '; if(type == SENDLIST_FULL && ss->Attached) { ast='*'; sendlistlinked++; } if(ss->Feed) ast='%'; sendlisttotal++; if(ss->WeekKB == -1) strcpy(buf,"?"); else sprintf(buf,"%ld",ss->WeekKB); if(strlen(ss->Tagname)<=28) { afAddLine(afr,"%lc%-28.28s %-33.33s %8.8s",ast,ss->Tagname,ss->Desc,buf); } else { afAddLine(afr,"%lc%-70.70s",ast,ss->Tagname); afAddLine(afr,"%lc%-28.28s %-33.33s %8.8s",' ',"",ss->Desc,buf); } lastss=ss; } switch(type) { case SENDLIST_QUERY: afAddLine(afr,"\x0d%lu linked areas.",sendlisttotal); afAddLine(afr,"A '%%' means that you are the feed for the area."); break; case SENDLIST_UNLINKED: afAddLine(afr,"\x0d%lu unlinked areas.",sendlisttotal); break; case SENDLIST_FULL: afAddLine(afr,"\x0dTotally %lu areas, you are connected to %lu of them.",sendlisttotal,sendlistlinked); afAddLine(afr,"A '*' means that you are connected to the area."); afAddLine(afr,"A '%%' means that you are the feed for the area."); break; } afSendMessage(afr); afFreeReply(afr); FreeSortList(); } void rawSendHelp(struct Node4D *from4d,uchar *toname,struct ConfigNode *cnode) { uchar helpbuf[100]; osFile fh; struct afReply *afr; LogWrite(4,AREAFIX,"AreaFix: Sending help file to %lu:%lu/%lu.%lu", cnode->Node.Zone, cnode->Node.Net, cnode->Node.Node, cnode->Node.Point); if(!(afr=afInitReply(config.cfg_Sysop,from4d,toname,&cnode->Node,"AreaFix help"))) return; if(!(fh=osOpen(config.cfg_AreaFixHelp,MODE_OLDFILE))) { ulong err=osError(); LogWrite(1,SYSTEMERR,"AreaFix: Unable to open %s",config.cfg_AreaFixHelp); LogWrite(1,SYSTEMERR,"AreaFix: Error: %s",osErrorMsg(err)); afAddLine(afr,"*** Error *** : Couldn't open help file"); } else { while(osFGets(fh,helpbuf,100) && !nomem) { if(helpbuf[0]!=0) helpbuf[strlen(helpbuf)-1]=0; afAddLine(afr,"%s",helpbuf); } osClose(fh); } afSendMessage(afr); afFreeReply(afr); } void rawSendInfo(struct Node4D *from4d,uchar *toname,struct ConfigNode *cnode) { int c; struct afReply *afr; LogWrite(4,AREAFIX,"AreaFix: Sending configuration info to %lu:%lu/%lu.%lu", cnode->Node.Zone, cnode->Node.Net, cnode->Node.Node, cnode->Node.Point); if(!(afr=afInitReply(config.cfg_Sysop,from4d,toname,&cnode->Node,"AreaFix configuration info"))) return; afAddLine(afr,"Configuration for %lu:%lu/%lu.%lu:", cnode->Node.Zone, cnode->Node.Net, cnode->Node.Node, cnode->Node.Point); afAddLine(afr,""); afAddLine(afr," Sysop: %s",cnode->SysopName); afAddLine(afr,"Packet password: %s",cnode->PacketPW); afAddLine(afr,"Areafix password: %s",cnode->AreafixPW); if(!cnode->Packer) { afAddLine(afr," Packer: No packer"); } else { afAddLine(afr," Packer: %s",cnode->Packer->Name); } afAddLine(afr,""); if(cnode->Flags & NODE_PASSIVE) afAddLine(afr," * You are passive and will not receive any echomail messages"); if(cnode->Flags & NODE_TINYSEENBY) afAddLine(afr," * You receive messages with tiny SEEN-BY lines"); if(cnode->Flags & NODE_NOSEENBY) afAddLine(afr," * You receive messages without SEEN-BY lines"); if(cnode->Flags & NODE_FORWARDREQ) afAddLine(afr," * You may do forward-requests"); if(cnode->Flags & NODE_NOTIFY) afAddLine(afr," * You will receive notifications"); if(cnode->Flags & NODE_PACKNETMAIL) afAddLine(afr," * Netmail to you will be packed"); if(cnode->Flags & NODE_AUTOADD) afAddLine(afr," * New areas from you will be auto-added"); afAddLine(afr,""); afAddLine(afr,"You have full access to these groups:"); afAddLine(afr,""); for(c='A';c<='Z';c++) if(CheckFlags(c,cnode->Groups) && !CheckFlags(c,cnode->ReadOnlyGroups)) { if(config.cfg_GroupNames[c-'A'][0]!=0) afAddLine(afr,"%lc: %s",c,config.cfg_GroupNames[c-'A']); else afAddLine(afr,"%lc",c); } afAddLine(afr,""); afAddLine(afr,"You have read-only access to these groups:"); afAddLine(afr,""); for(c='A';c<='Z';c++) if(CheckFlags(c,cnode->ReadOnlyGroups)) { if(config.cfg_GroupNames[c-'A']) afAddLine(afr,"%lc: %s",c,config.cfg_GroupNames[c-'A']); else afAddLine(afr,"%lc",c); } afSendMessage(afr); afFreeReply(afr); } void afRawPrepareMessage(void); struct afReply *afInitReply(uchar *fromname,struct Node4D *from4d,uchar *toname,struct Node4D *to4d,uchar *subject) { struct afReply *afr; if(!(afr=osAllocCleared(sizeof(struct afReply)))) { nomem=TRUE; return(NULL); } if(!(afr->mm=mmAlloc())) { nomem=TRUE; osFree(afr); return(NULL); } strcpy(afr->mm->From,fromname); Copy4D(&afr->mm->OrigNode,from4d); strcpy(afr->mm->To,toname); Copy4D(&afr->mm->DestNode,to4d); strcpy(afr->subject,subject); afr->mm->Attr = FLAG_PVT; MakeFidoDate(time(NULL),afr->mm->DateTime); afr->mm->Flags |= MMFLAG_AUTOGEN; MakeNetmailKludges(afr->mm); afr->lines=0; afr->part=1; return(afr); } void afFreeReply(struct afReply *afr) { mmFree(afr->mm); } void afAddLine(struct afReply *afr,uchar *fmt,...) { va_list args; uchar buf[200]; if(afr->lines >= config.cfg_AreaFixMaxLines-2 && config.cfg_AreaFixMaxLines!=0) { strcpy(buf,"\x0d(Continued in next message)\x0d"); mmAddLine(afr->mm,buf); sprintf(afr->mm->Subject,"%s (part %ld)",afr->subject,afr->part); afSendMessage(afr); jbFreeList(&afr->mm->TextChunks); MakeFidoDate(time(NULL),afr->mm->DateTime); afr->mm->Flags |= MMFLAG_AUTOGEN; MakeNetmailKludges(afr->mm); strcpy(buf,"(Continued from previous message)\x0d\x0d"); mmAddLine(afr->mm,buf); afr->lines=2; afr->part++; } va_start(args, fmt); vsprintf(buf,fmt,args); va_end(args); strcat(buf,"\x0d"); mmAddLine(afr->mm,buf); afr->lines++; } void afSendMessage(struct afReply *afr) { if(afr->part != 1) sprintf(afr->mm->Subject,"%s (part %ld)",afr->subject,afr->part); else strcpy(afr->mm->Subject,afr->subject); HandleMessage(afr->mm); } void RemoteAreafixAdd(uchar *area,struct ConfigNode *node) { struct RemoteAFCommand *cmd; if(!(cmd=(struct RemoteAFCommand *)osAllocCleared(sizeof(struct RemoteAFCommand)))) { nomem=TRUE; return; } if(node->Flags & NODE_AFNEEDSPLUS) sprintf(cmd->Command,"+%.78s",area); else sprintf(cmd->Command,"%.78s",area); cmd->Command[70]=0; jbAddNode(&node->RemoteAFList,(struct jbNode *)cmd); } void RemoteAreafixRemove(uchar *area,struct ConfigNode *node) { struct RemoteAFCommand *cmd; if(!(cmd=(struct RemoteAFCommand *)osAllocCleared(sizeof(struct RemoteAFCommand)))) { nomem=TRUE; return; } sprintf(cmd->Command,"-%.78s",area); cmd->Command[70]=0; jbAddNode(&node->RemoteAFList,(struct jbNode *)cmd); } void SendRemoteAreafix(void) { struct Route *tmproute; struct ConfigNode *node; struct RemoteAFCommand *cmd; uchar buf[200]; struct MemMessage *mm; for(node=(struct ConfigNode *)config.CNodeList.First;node;node=node->Next) if(node->RemoteAFList.First) { if(!(mm=mmAlloc())) { nomem=TRUE; return; } for(tmproute=(struct Route *)config.RouteList.First;tmproute;tmproute=tmproute->Next) if(Compare4DPat(&tmproute->Pattern,&node->Node)==0) break; Copy4D(&mm->DestNode,&node->Node); Copy4D(&mm->OrigNode,&tmproute->Aka->Node); strcpy(mm->From,config.cfg_Sysop); strcpy(mm->To,node->RemoteAFName); strcpy(mm->Subject,node->RemoteAFPw); mm->Attr = FLAG_PVT; MakeFidoDate(time(NULL),mm->DateTime); mm->Flags |= MMFLAG_AUTOGEN; MakeNetmailKludges(mm); if(config.cfg_Flags & CFG_ADDTID) AddTID(mm); for(cmd=(struct RemoteAFCommand *)node->RemoteAFList.First;cmd;cmd=cmd->Next) { sprintf(buf,"%s\x0d",cmd->Command); mmAddLine(mm,buf); } mmAddLine(mm,"---\x0dGenerated by CrashMail "VERSION"\x0d"); HandleMessage(mm); mmFree(mm); jbFreeList(&node->RemoteAFList); } } bool CheckFlags(uchar group,uchar *node) { uchar c; for(c=0;cNext) { if((arealist->Flags & AREALIST_FORWARD) && CheckFlags(arealist->Group,flags)) { if((fh=osOpen(arealist->AreaFile,MODE_OLDFILE))) { while(osFGets(fh,buf,199)) { for(c=0;buf[c]>32;c++); buf[c]=0; if(stricmp(buf,tagname)==0) { osClose(fh); return(arealist); } } osClose(fh); } else { ulong err=osError(); LogWrite(1,SYSTEMERR,"Failed to open file %s",arealist->AreaFile); LogWrite(1,SYSTEMERR,"Error: %s",osErrorMsg(err)); } } } return(NULL); } void DoSendAFList(short type,struct ConfigNode *cnode) { struct Route *tmproute; for(tmproute=(struct Route *)config.RouteList.First;tmproute;tmproute=tmproute->Next) if(Compare4DPat(&tmproute->Pattern,&cnode->Node)==0) break; if(!tmproute) { LogWrite(1,TOSSINGERR,"No route found for %ld:%ld/%ld.%ld", cnode->Node.Zone, cnode->Node.Net, cnode->Node.Node, cnode->Node.Point); return; } switch(type) { case SENDLIST_FULL: rawSendList(SENDLIST_FULL,&tmproute->Aka->Node,cnode->SysopName,cnode); break; case SENDLIST_QUERY: rawSendList(SENDLIST_QUERY,&tmproute->Aka->Node,cnode->SysopName,cnode); break; case SENDLIST_UNLINKED: rawSendList(SENDLIST_UNLINKED,&tmproute->Aka->Node,cnode->SysopName,cnode); break; case SENDLIST_INFO: rawSendInfo(&tmproute->Aka->Node,cnode->SysopName,cnode); break; case SENDLIST_HELP: rawSendHelp(&tmproute->Aka->Node,cnode->SysopName,cnode); break; } } crashmail-0.71/src/crashmail/areafix.h0100644000000000000000000000050407300264670016430 0ustar rootroot #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); crashmail-0.71/src/crashmail/scan.c0100644000000000000000000001602507764166256015754 0ustar rootroot#include "crashmail.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,"%lu messages exported",scan_total); } } bool ScanHandle(struct MemMessage *mm) { uchar buf[50]; if(mm->Area[0]==0) { Print4D(&mm->DestNode,buf); LogWrite(4,TOSSINGINFO,"Exporting message #%lu from \"%s\" to \"%s\" at %s", mm->msgnum, mm->From, mm->To, buf); } else { LogWrite(4,TOSSINGINFO,"Exporting message #%lu 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(uchar *file) { osFile fh; uchar 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(uchar *file) { osFile fh; uchar 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(uchar *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); } crashmail-0.71/src/crashmail/scan.h0100644000000000000000000000015207762202323015733 0ustar rootrootbool Scan(void); bool ScanList(uchar *file); bool ScanDotJam(uchar *file); bool ScanArea(uchar *tagname); crashmail-0.71/src/crashmail/toss.c0100644000000000000000000001566507764162243016021 0ustar rootroot#include "crashmail.h" bool Compare(uchar *str,uchar *recog) { ulong c,d; uchar comp; uchar buf[5]; d=0; for(c=0;dNext) 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 -- %lu messages (%lu dupes)",area->Tagname,area->NewTexts,area->NewDupes); else if(area->NewTexts) LogWrite(3,TOSSINGINFO,"Area %s -- %lu 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(uchar *file,struct osFileEntry *fe) { struct Packer *tmppacker; uchar 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: %lu",arcres); sprintf(buf2,"Unarchiving with %s failed: %u",tmppacker->Name,arcres); BadFile(file,buf2); } if(!osReadDir(config.cfg_TempDir,&FEList,IsPkt)) { ulong 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(uchar *dir) { struct osFileEntry *fe; struct jbList PktFEList; struct jbList ArcFEList; uchar buf[200]; LogWrite(3,ACTIONINFO,"Tossing files in %s...",dir); if(!BeforeScanToss()) return(FALSE); /* Notify about old bad files */ if(!osReadDir(dir,&PktFEList,IsBad)) { ulong 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)) { ulong 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)) { ulong 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(uchar *file) { struct osFileEntry *fe; LogWrite(3,ACTIONINFO,"Tossing file %s...",file); if(!(fe=osGetFileEntry(file))) { ulong 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); } crashmail-0.71/src/crashmail/toss.h0100644000000000000000000000006707300264670016005 0ustar rootrootbool TossFile(uchar *file); bool TossDir(uchar *dir); crashmail-0.71/src/crashmail/node4dpat.c0100644000000000000000000002222707763153646016711 0ustar rootroot#include "crashmail.h" bool rawParse4DPat(uchar *buf, struct Node4DPat *node) { ulong c=0,tempc=0; uchar 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;cZone,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); } bool Parse4DPat(uchar *buf, struct Node4DPat *node) { bool res; node->Zone[0]=0; node->Net[0]=0; node->Node[0]=0; node->Point[0]=0; if(strnicmp(buf,"ZONE ",5)==0) { node->Type=PAT_ZONE; res=rawParse4DPat(&buf[5],node); strcpy(node->Zone,node->Node); node->Net[0]=0; node->Node[0]=0; node->Point[0]=0; } else if(strnicmp(buf,"REGION ",7)==0) { node->Type=PAT_REGION; res=rawParse4DPat(&buf[7],node); node->Node[0]=0; node->Point[0]=0; } else if(strnicmp(buf,"NET ",4)==0) { node->Type=PAT_NET; res=rawParse4DPat(&buf[4],node); node->Node[0]=0; node->Point[0]=0; } else if(strnicmp(buf,"HUB ",4)==0) { node->Type=PAT_HUB; res=rawParse4DPat(&buf[4],node); node->Point[0]=0; } else if(strnicmp(buf,"NODE ",5)==0) { node->Type=PAT_NODE; res=rawParse4DPat(&buf[5],node); node->Point[0]=0; } else { node->Type=PAT_PATTERN; res=rawParse4DPat(buf,node); } return(res); } bool Parse4DDestPat(uchar *buf, struct Node4DPat *node) { bool res; node->Zone[0]=0; node->Net[0]=0; node->Node[0]=0; node->Point[0]=0; res=TRUE; if(stricmp(buf,"ZONE")==0) { node->Type=PAT_ZONE; } else if(stricmp(buf,"REGION")==0) { node->Type=PAT_REGION; } else if(stricmp(buf,"NET")==0) { node->Type=PAT_NET; } else if(stricmp(buf,"HUB")==0) { node->Type=PAT_HUB; } else if(stricmp(buf,"NODE")==0) { node->Type=PAT_NODE; } else { node->Type=PAT_PATTERN; res=rawParse4DPat(buf,node); } return(res); } int NodeCompare(uchar *pat,ushort num) { uchar buf[10],c; sprintf(buf,"%u",num); if(pat[0]==0) return(0); for(c=0;cType) { case PAT_PATTERN: 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); case PAT_ZONE: if(NodeCompare(nodepat->Zone,node->Zone)!=0) return(1); return(0); case PAT_REGION: if(!nodelistopen) return(1); Copy4D(&n4d,node); n4d.Point=0; num=(*config.cfg_NodelistType->nlGetRegion)(&n4d); if(num == -1) return(1); if(node->Zone!=0) if(NodeCompare(nodepat->Zone,node->Zone)!=0) return(1); if(NodeCompare(nodepat->Net,num)!=0) return(1); return(0); case PAT_NET: if(node->Zone!=0) if(NodeCompare(nodepat->Zone,node->Zone)!=0) return(1); if(NodeCompare(nodepat->Net,node->Net)!=0) return(1); return(0); case PAT_HUB: if(!nodelistopen) return(1); Copy4D(&n4d,node); n4d.Point=0; num=(*config.cfg_NodelistType->nlGetHub)(&n4d); if(num == -1) return(1); 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,num)!=0) return(1); return(0); case PAT_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); return(0); } return(1); } void Print4DPat(struct Node4DPat *pat,uchar *dest) { switch(pat->Type) { case PAT_PATTERN: sprintf(dest,"%s:%s/%s.%s",pat->Zone,pat->Net,pat->Node,pat->Point); break; case PAT_ZONE: sprintf(dest,"ZONE %s",pat->Zone); break; case PAT_REGION: sprintf(dest,"REGION %s:%s",pat->Zone,pat->Net); break; case PAT_NET: sprintf(dest,"NET %s:%s",pat->Zone,pat->Net); break; case PAT_HUB: sprintf(dest,"HUB %s:%s/%s",pat->Zone,pat->Net,pat->Node); break; case PAT_NODE: sprintf(dest,"NODE %s:%s/%s",pat->Zone,pat->Net,pat->Node); break; } } void Print4DDestPat(struct Node4DPat *pat,uchar *dest) { switch(pat->Type) { case PAT_PATTERN: sprintf(dest,"%s:%s/%s.%s",pat->Zone,pat->Net,pat->Node,pat->Point); break; case PAT_ZONE: sprintf(dest,"ZONE"); break; case PAT_REGION: sprintf(dest,"REGION"); break; case PAT_NET: sprintf(dest,"NET"); break; case PAT_HUB: sprintf(dest,"HUB"); break; case PAT_NODE: sprintf(dest,"NODE"); break; } } bool Check4DPatNodelist(struct Node4DPat *pat) { if(pat->Type == PAT_HUB || pat->Type == PAT_REGION) return(FALSE); return(TRUE); } bool Parse2DPat(uchar *buf, struct Node2DPat *node) { ulong c=0,tempc=0; uchar temp[10]; bool GotNet=FALSE; strcpy(node->Net,"*"); strcpy(node->Node,"*"); if(strcmp(buf,"*")==0) return(TRUE); for(c=0;cNet,temp); GotNet=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); } strcpy(node->Node,temp); return(TRUE); } int Compare2DPat(struct Node2DPat *nodepat,ushort net,ushort node) { if(NodeCompare(nodepat->Net, net )!=0) return(1); if(NodeCompare(nodepat->Node, node)!=0) return(1); return(0); } /* Expand destpat */ bool iswildcard(uchar *str) { int c; for(c=0;cType == PAT_REGION) region=(*config.cfg_NodelistType->nlGetRegion)(&n4d); if(temproute->Type == PAT_HUB) hub=(*config.cfg_NodelistType->nlGetHub)(&n4d); if(region == -1) region=0; if(hub == -1) hub=0; } if(region == 0) region=dest->Net; switch(temproute->Type) { case PAT_PATTERN: sendto->Zone = iswildcard(temproute->Zone) ? dest->Zone : atoi(temproute->Zone); sendto->Net = iswildcard(temproute->Net) ? dest->Net : atoi(temproute->Net); sendto->Node = iswildcard(temproute->Node) ? dest->Node : atoi(temproute->Node); sendto->Point = iswildcard(temproute->Point) ? dest->Point : atoi(temproute->Point); break; case PAT_ZONE: sendto->Zone = dest->Zone; sendto->Net = dest->Zone; sendto->Node = 0; sendto->Point = 0; break; case PAT_REGION: sendto->Zone = dest->Zone; sendto->Net = region; sendto->Node = 0; sendto->Point = 0; break; case PAT_NET: sendto->Zone = dest->Zone; sendto->Net = dest->Net; sendto->Node = 0; sendto->Point = 0; break; case PAT_HUB: sendto->Zone = dest->Zone; sendto->Net = dest->Net; sendto->Node = hub; sendto->Point = 0; break; case PAT_NODE: sendto->Zone = dest->Zone; sendto->Net = dest->Net; sendto->Node = dest->Node; sendto->Point = 0; break; } } crashmail-0.71/src/crashmail/node4dpat.h0100644000000000000000000000162007300264670016673 0ustar rootroot#ifndef NODE4DPAT_H #define NODE4DPAT_H #define PAT_PATTERN 0 #define PAT_ZONE 1 #define PAT_REGION 2 #define PAT_NET 3 #define PAT_HUB 4 #define PAT_NODE 5 struct Node4DPat { uchar Type; uchar Zone[10]; uchar Point[10]; uchar Net[10]; uchar Node[10]; }; struct Node2DPat { uchar Net[10]; uchar Node[10]; }; bool Parse4DPat(uchar *buf, struct Node4DPat *node); bool Parse4DDestPat(uchar *buf, struct Node4DPat *node); int Compare4DPat(struct Node4DPat *nodepat,struct Node4D *node); void Print4DPat(struct Node4DPat *pat,uchar *dest); void Print4DDestPat(struct Node4DPat *pat,uchar *dest); bool Check4DPatNodelist(struct Node4DPat *pat); bool Parse2DPat(uchar *buf, struct Node2DPat *node); int Compare2DPat(struct Node2DPat *nodepat,ushort net,ushort node); void ExpandNodePat(struct Node4DPat *temproute,struct Node4D *dest,struct Node4D *sendto); #endif crashmail-0.71/src/crashmail/safedel.c0100644000000000000000000000067107300264670016414 0ustar rootroot#include "crashmail.h" bool SafeDelete(uchar *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); } crashmail-0.71/src/crashmail/safedel.h0100644000000000000000000000007407300264670016416 0ustar rootrootbool SafeDelete(uchar *file); void ProcessSafeDelete(void); crashmail-0.71/src/crashmail/crashmail.c0100644000000000000000000003706007764156625016774 0ustar rootroot#include "crashmail.h" #ifdef PLATFORM_AMIGA const uchar ver[]="\0$VER: CrashMail II/" OS_PLATFORM_NAME " " VERSION " " __AMIGADATE__; #endif /*********************************** Global *******************************/ struct jbList PktList; struct jbList DeleteList; bool nomem; bool ioerror; ulong ioerrornum; ulong toss_read; ulong toss_bad; ulong toss_route; ulong toss_import; ulong toss_written; ulong toss_dupes; ulong scan_total; ulong rescan_total; bool no_security; int handle_nesting; struct ConfigNode *RescanNode; ulong DayStatsWritten; /* The area statistics are updated until this day */ struct Config config; bool ctrlc; bool nodelistopen; uchar *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; uchar errbuf[200]; ulong 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;dLast8Days[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; uchar 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)) { ulong 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 CrashMail II 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(uchar *areaname,uchar *node,ulong 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 %lu:%lu/%lu.%lu",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 %lu messages",rescan_total); AfterScanToss(success); return(success); } bool SendAFList(uchar *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 %lu:%lu/%lu.%lu",n4d.Zone,n4d.Net,n4d.Node,n4d.Point); return(FALSE); } } AfterScanToss(TRUE); if(nomem || ioerror) return(FALSE); return(TRUE); } bool RemoveArea(uchar *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(uchar *file) { uchar 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(uchar *file) { uchar buf[200]; strcpy(buf,file); strcat(buf,".busy"); osDelete(buf); } void CleanUp(int err) { if(done_welcomemsg) LogWrite(2,SYSTEMINFO,"CrashMail 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) { uchar *cfg; ulong cfgline; short seconderr; uchar 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=(uchar *)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("CrashMail 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 %ld:\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,"CrashMail II %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((uchar *)args[ARG_TOSSFILE].data); if(args[ARG_TOSSDIR].data) TossDir((uchar *)args[ARG_TOSSDIR].data); else if(args[ARG_SCAN].data) Scan(); else if(args[ARG_SCANAREA].data) ScanArea((uchar *)args[ARG_SCANAREA].data); else if(args[ARG_SCANLIST].data) ScanList((uchar *)args[ARG_SCANLIST].data); else if(args[ARG_SCANDOTJAM].data) ScanDotJam((uchar *)args[ARG_SCANDOTJAM].data); else if(args[ARG_RESCAN].data) { ulong num; num=0; if(args[ARG_RESCANMAX].data) num=atoi((uchar *)args[ARG_RESCANMAX].data); if(!args[ARG_RESCANNODE].data) LogWrite(1,USERERR,"No RESCANNODE specified"); else Rescan((uchar *)args[ARG_RESCAN].data,(uchar *)args[ARG_RESCANNODE].data,num); } else if(args[ARG_SENDLIST].data) SendAFList((uchar *)args[ARG_SENDLIST].data,SENDLIST_FULL); else if(args[ARG_SENDQUERY].data) SendAFList((uchar *)args[ARG_SENDQUERY].data,SENDLIST_QUERY); else if(args[ARG_SENDUNLINKED].data) SendAFList((uchar *)args[ARG_SENDUNLINKED].data,SENDLIST_UNLINKED); else if(args[ARG_SENDHELP].data) SendAFList((uchar *)args[ARG_SENDHELP].data,SENDLIST_HELP); else if(args[ARG_SENDINFO].data) SendAFList((uchar *)args[ARG_SENDINFO].data,SENDLIST_INFO); else if(args[ARG_REMOVE].data) RemoveArea((uchar *)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); } crashmail-0.71/src/crashmail/crashmail.h0100644000000000000000000000327710073763045016767 0ustar rootroot#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #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" #define VERSION_MAJOR 0 #define VERSION_MINOR 71 #define VERSION "0.71" #define TID_VERSION "0.71" extern struct jbList PktList; extern struct jbList DeleteList; extern bool nomem; extern bool ioerror; extern ulong ioerrornum; extern ulong toss_read; extern ulong toss_bad; extern ulong toss_route; extern ulong toss_import; extern ulong toss_written; extern ulong toss_dupes; extern ulong scan_total; extern ulong rescan_total; extern bool no_security; extern int handle_nesting; extern struct ConfigNode *RescanNode; extern ulong 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 uchar *prinames[]; crashmail-0.71/src/jamlib/0040755000000000000000000000000010073763620014137 5ustar rootrootcrashmail-0.71/src/jamlib/structrw.c0100644000000000000000000002067610073762726016216 0ustar rootroot/* structrw - Platform-independent reading and writing of JAM structs Copyright (C) 1999 Johan Billing This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Changes made by Johan Billing 2003-10-22 - Added #include */ #include #include #include "jam.h" #include "structrw.h" ushort jamgetuword(uchar *buf,ulong offset) { return (ushort) buf[offset]+ buf[offset+1]*256; } void jamputuword(uchar *buf,ulong offset,ushort num) { buf[offset]=num%256; buf[offset+1]=num/256; } void jamputulong(uchar *buf,ulong offset,ulong 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; } ulong jamgetulong(uchar *buf,ulong offset) { return (ulong) buf[offset]+ buf[offset+1]*256+ buf[offset+2]*256*256+ buf[offset+3]*256*256*256; } int freadjambaseheader(FILE *fp,s_JamBaseHeader *s_JamBaseHeader) { uchar buf[SIZE_JAMBASEHEADER]; if(fread(buf,SIZE_JAMBASEHEADER,1,fp) != 1) return 0; memcpy(s_JamBaseHeader->Signature,&buf[JAMBASEHEADER_SIGNATURE],4); s_JamBaseHeader->DateCreated = jamgetulong(buf,JAMBASEHEADER_DATECREATED); s_JamBaseHeader->ModCounter = jamgetulong(buf,JAMBASEHEADER_MODCOUNTER); s_JamBaseHeader->ActiveMsgs = jamgetulong(buf,JAMBASEHEADER_ACTIVEMSGS); s_JamBaseHeader->PasswordCRC = jamgetulong(buf,JAMBASEHEADER_PASSWORDCRC); s_JamBaseHeader->BaseMsgNum = jamgetulong(buf,JAMBASEHEADER_BASEMSGNUM); memcpy(s_JamBaseHeader->RSRVD,&buf[JAMBASEHEADER_RSRVD],1000); return 1; } int fwritejambaseheader(FILE *fp,s_JamBaseHeader *s_JamBaseHeader) { uchar buf[SIZE_JAMBASEHEADER]; memcpy(&buf[JAMBASEHEADER_SIGNATURE],s_JamBaseHeader->Signature,4); jamputulong(buf,JAMBASEHEADER_DATECREATED, s_JamBaseHeader->DateCreated); jamputulong(buf,JAMBASEHEADER_MODCOUNTER, s_JamBaseHeader->ModCounter); jamputulong(buf,JAMBASEHEADER_ACTIVEMSGS, s_JamBaseHeader->ActiveMsgs); jamputulong(buf,JAMBASEHEADER_PASSWORDCRC, s_JamBaseHeader->PasswordCRC ); jamputulong(buf,JAMBASEHEADER_BASEMSGNUM, s_JamBaseHeader->BaseMsgNum); memcpy(&buf[JAMBASEHEADER_RSRVD],s_JamBaseHeader->RSRVD,1000); if(fwrite(buf,SIZE_JAMBASEHEADER,1,fp) != 1) return 0; return 1; } int freadjammsgheader(FILE *fp,s_JamMsgHeader *s_JamMsgHeader) { uchar buf[SIZE_JAMMSGHEADER]; if(fread(buf,SIZE_JAMMSGHEADER,1,fp) != 1) return 0; memcpy(s_JamMsgHeader->Signature,&buf[JAMMSGHEADER_SIGNATURE],4); s_JamMsgHeader->Revision = jamgetuword(buf,JAMMSGHEADER_REVISION); s_JamMsgHeader->ReservedWord = jamgetuword(buf,JAMMSGHEADER_RESERVEDWORD); s_JamMsgHeader->SubfieldLen = jamgetulong(buf,JAMMSGHEADER_SUBFIELDLEN); s_JamMsgHeader->TimesRead = jamgetulong(buf,JAMMSGHEADER_TIMESREAD); s_JamMsgHeader->MsgIdCRC = jamgetulong(buf,JAMMSGHEADER_MSGIDCRC); s_JamMsgHeader->ReplyCRC = jamgetulong(buf,JAMMSGHEADER_REPLYCRC); s_JamMsgHeader->ReplyTo = jamgetulong(buf,JAMMSGHEADER_REPLYTO); s_JamMsgHeader->Reply1st = jamgetulong(buf,JAMMSGHEADER_REPLY1ST); s_JamMsgHeader->ReplyNext = jamgetulong(buf,JAMMSGHEADER_REPLYNEXT); s_JamMsgHeader->DateWritten = jamgetulong(buf,JAMMSGHEADER_DATEWRITTEN); s_JamMsgHeader->DateReceived = jamgetulong(buf,JAMMSGHEADER_DATERECEIVED); s_JamMsgHeader->DateProcessed = jamgetulong(buf,JAMMSGHEADER_DATEPROCESSED); s_JamMsgHeader->MsgNum = jamgetulong(buf,JAMMSGHEADER_MSGNUM); s_JamMsgHeader->Attribute = jamgetulong(buf,JAMMSGHEADER_ATTRIBUTE); s_JamMsgHeader->Attribute2 = jamgetulong(buf,JAMMSGHEADER_ATTRIBUTE2); s_JamMsgHeader->TxtOffset = jamgetulong(buf,JAMMSGHEADER_TXTOFFSET); s_JamMsgHeader->TxtLen = jamgetulong(buf,JAMMSGHEADER_TXTLEN); s_JamMsgHeader->PasswordCRC = jamgetulong(buf,JAMMSGHEADER_PASSWORDCRC); s_JamMsgHeader->Cost = jamgetulong(buf,JAMMSGHEADER_COST); return 1; } int fwritejammsgheader(FILE *fp,s_JamMsgHeader *s_JamMsgHeader) { uchar buf[SIZE_JAMMSGHEADER]; memcpy(&buf[JAMMSGHEADER_SIGNATURE],s_JamMsgHeader->Signature,4); jamputuword(buf,JAMMSGHEADER_REVISION, s_JamMsgHeader->Revision); jamputuword(buf,JAMMSGHEADER_RESERVEDWORD, s_JamMsgHeader->ReservedWord); jamputulong(buf,JAMMSGHEADER_SUBFIELDLEN, s_JamMsgHeader->SubfieldLen); jamputulong(buf,JAMMSGHEADER_TIMESREAD, s_JamMsgHeader->TimesRead); jamputulong(buf,JAMMSGHEADER_MSGIDCRC, s_JamMsgHeader->MsgIdCRC); jamputulong(buf,JAMMSGHEADER_REPLYCRC, s_JamMsgHeader->ReplyCRC ); jamputulong(buf,JAMMSGHEADER_REPLYTO, s_JamMsgHeader->ReplyTo); jamputulong(buf,JAMMSGHEADER_REPLY1ST, s_JamMsgHeader->Reply1st); jamputulong(buf,JAMMSGHEADER_REPLYNEXT, s_JamMsgHeader->ReplyNext); jamputulong(buf,JAMMSGHEADER_DATEWRITTEN, s_JamMsgHeader->DateWritten); jamputulong(buf,JAMMSGHEADER_DATERECEIVED, s_JamMsgHeader->DateReceived ); jamputulong(buf,JAMMSGHEADER_DATEPROCESSED, s_JamMsgHeader->DateProcessed); jamputulong(buf,JAMMSGHEADER_MSGNUM, s_JamMsgHeader->MsgNum); jamputulong(buf,JAMMSGHEADER_ATTRIBUTE, s_JamMsgHeader->Attribute); jamputulong(buf,JAMMSGHEADER_ATTRIBUTE2, s_JamMsgHeader->Attribute2); jamputulong(buf,JAMMSGHEADER_TXTOFFSET, s_JamMsgHeader->TxtOffset); jamputulong(buf,JAMMSGHEADER_TXTLEN, s_JamMsgHeader->TxtLen); jamputulong(buf,JAMMSGHEADER_PASSWORDCRC, s_JamMsgHeader->PasswordCRC); jamputulong(buf,JAMMSGHEADER_COST, s_JamMsgHeader->Cost); if(fwrite(buf,SIZE_JAMMSGHEADER,1,fp) != 1) return 0; return 1; } int freadjamindex(FILE *fp,s_JamIndex *s_JamIndex) { uchar buf[SIZE_JAMINDEX]; if(fread(buf,SIZE_JAMINDEX,1,fp) != 1) return 0; s_JamIndex->UserCRC = jamgetulong(buf,JAMINDEX_USERCRC); s_JamIndex->HdrOffset = jamgetulong(buf,JAMINDEX_HDROFFSET); return 1; } int fwritejamindex(FILE *fp,s_JamIndex *s_JamIndex) { uchar buf[SIZE_JAMINDEX]; jamputulong(buf,JAMINDEX_USERCRC, s_JamIndex->UserCRC); jamputulong(buf,JAMINDEX_HDROFFSET, s_JamIndex->HdrOffset); if(fwrite(buf,SIZE_JAMINDEX,1,fp) != 1) return 0; return 1; } int freadjamlastread(FILE *fp,s_JamLastRead *s_JamLastRead) { uchar buf[SIZE_JAMLASTREAD]; if(fread(buf,SIZE_JAMLASTREAD,1,fp) != 1) return 0; s_JamLastRead->UserCRC = jamgetulong(buf,JAMLASTREAD_USERCRC); s_JamLastRead->UserID = jamgetulong(buf,JAMLASTREAD_USERID); s_JamLastRead->LastReadMsg = jamgetulong(buf,JAMLASTREAD_LASTREADMSG); s_JamLastRead->HighReadMsg = jamgetulong(buf,JAMLASTREAD_HIGHREADMSG); return 1; } int fwritejamlastread(FILE *fp,s_JamLastRead *s_JamLastRead) { uchar buf[SIZE_JAMLASTREAD]; jamputulong(buf,JAMLASTREAD_USERCRC,s_JamLastRead->UserCRC); jamputulong(buf,JAMLASTREAD_USERID,s_JamLastRead->UserID); jamputulong(buf,JAMLASTREAD_LASTREADMSG,s_JamLastRead->LastReadMsg); jamputulong(buf,JAMLASTREAD_HIGHREADMSG,s_JamLastRead->HighReadMsg); if(fwrite(buf,SIZE_JAMLASTREAD,1,fp) != 1) return 0; return 1; } int fwritejamsavesubfield(FILE *fp,s_JamSaveSubfield *s_JamSaveSubfield) { uchar buf[SIZE_JAMLASTREAD]; jamputuword(buf,JAMSAVESUBFIELD_LOID, s_JamSaveSubfield->LoID); jamputuword(buf,JAMSAVESUBFIELD_HIID, s_JamSaveSubfield->HiID); jamputulong(buf,JAMSAVESUBFIELD_DATLEN, s_JamSaveSubfield->DatLen); if(fwrite(buf,SIZE_JAMSAVESUBFIELD,1,fp) != 1) return 0; return 1; } void getjamsubfield(uchar *buf,s_JamSubfield *Subfield_S) { Subfield_S->LoID = jamgetuword(buf,JAMSAVESUBFIELD_LOID); Subfield_S->HiID = jamgetuword(buf,JAMSAVESUBFIELD_HIID); Subfield_S->DatLen = jamgetulong(buf,JAMSAVESUBFIELD_DATLEN); Subfield_S->Buffer = (uchar *) buf + SIZE_JAMSAVESUBFIELD; } crashmail-0.71/src/jamlib/structrw.h0100644000000000000000000000570310073762726016215 0ustar rootroot/* structrw - Platform-independent reading and writing of JAM structs Copyright (C) 1999 Johan Billing This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #define JAMBASEHEADER_SIGNATURE 0 #define JAMBASEHEADER_DATECREATED 4 #define JAMBASEHEADER_MODCOUNTER 8 #define JAMBASEHEADER_ACTIVEMSGS 12 #define JAMBASEHEADER_PASSWORDCRC 16 #define JAMBASEHEADER_BASEMSGNUM 20 #define JAMBASEHEADER_RSRVD 24 #define SIZE_JAMBASEHEADER 1024 #define JAMMSGHEADER_SIGNATURE 0 #define JAMMSGHEADER_REVISION 4 #define JAMMSGHEADER_RESERVEDWORD 6 #define JAMMSGHEADER_SUBFIELDLEN 8 #define JAMMSGHEADER_TIMESREAD 12 #define JAMMSGHEADER_MSGIDCRC 16 #define JAMMSGHEADER_REPLYCRC 20 #define JAMMSGHEADER_REPLYTO 24 #define JAMMSGHEADER_REPLY1ST 28 #define JAMMSGHEADER_REPLYNEXT 32 #define JAMMSGHEADER_DATEWRITTEN 36 #define JAMMSGHEADER_DATERECEIVED 40 #define JAMMSGHEADER_DATEPROCESSED 44 #define JAMMSGHEADER_MSGNUM 48 #define JAMMSGHEADER_ATTRIBUTE 52 #define JAMMSGHEADER_ATTRIBUTE2 56 #define JAMMSGHEADER_TXTOFFSET 60 #define JAMMSGHEADER_TXTLEN 64 #define JAMMSGHEADER_PASSWORDCRC 68 #define JAMMSGHEADER_COST 72 #define SIZE_JAMMSGHEADER 76 #define JAMINDEX_USERCRC 0 #define JAMINDEX_HDROFFSET 4 #define SIZE_JAMINDEX 8 #define JAMLASTREAD_USERCRC 0 #define JAMLASTREAD_USERID 4 #define JAMLASTREAD_LASTREADMSG 8 #define JAMLASTREAD_HIGHREADMSG 12 #define SIZE_JAMLASTREAD 16 #define JAMSAVESUBFIELD_LOID 0 #define JAMSAVESUBFIELD_HIID 2 #define JAMSAVESUBFIELD_DATLEN 4 #define SIZE_JAMSAVESUBFIELD 8 int freadjambaseheader(FILE *fp,s_JamBaseHeader *s_JamBaseHeader); int fwritejambaseheader(FILE *fp,s_JamBaseHeader *s_JamBaseHeader); int freadjammsgheader(FILE *fp,s_JamMsgHeader *s_JamMsgHeader); int fwritejammsgheader(FILE *fp,s_JamMsgHeader *s_JamMsgHeader); int freadjamindex(FILE *fp,s_JamIndex *s_JamIndex); int fwritejamindex(FILE *fp,s_JamIndex *s_JamIndex); int freadjamlastread(FILE *fp,s_JamLastRead *s_JamLastRead); int fwritejamlastread(FILE *fp,s_JamLastRead *s_JamLastRead); int fwritejamsavesubfield(FILE *fp,s_JamSaveSubfield *s_JamSaveSubfield); void getjamsubfield(uchar *buf,s_JamSubfield *Subfield_S); crashmail-0.71/src/jamlib/crc32.c0100644000000000000000000001063410073762726015226 0ustar rootroot/* Crc32 - CRC32-calculation for JAM Copyright (C) 2000 Johan Billing This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Changes made by Johan Billing 2003-10-22 - Fixed comparison between signed and unsigned variable in JAM_Crc32() */ #include "jam.h" ulong 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 }; /*********************************************************************** ** ** JAM_Crc32 - Calculates CRC-32 ** ***********************************************************************/ ulong JAM_Crc32(uchar *Buffer_PC, ulong Length_I) { ulong Crc_I; ulong c; Crc_I=0xffffffff; for(c=0;c < Length_I; c++) Crc_I=(Crc_I>>8) ^ crc32tab[(uchar)Crc_I ^ tolower(Buffer_PC[c])]; return(Crc_I); } crashmail-0.71/src/jamlib/LICENSE0100644000000000000000000006347610073762726015167 0ustar rootroot GNU LESSER GENERAL PUBLIC LICENSE Version 2.1, February 1999 Copyright (C) 1991, 1999 Free Software Foundation, Inc. 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. [This is the first released version of the Lesser GPL. It also counts as the successor of the GNU Library Public License, version 2, hence the version number 2.1.] Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public Licenses are intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This license, the Lesser General Public License, applies to some specially designated software packages--typically libraries--of the Free Software Foundation and other authors who decide to use it. You can use it too, but we suggest you first think carefully about whether this license or the ordinary General Public License is the better strategy to use in any particular case, based on the explanations below. When we speak of free software, we are referring to freedom of use, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish); that you receive source code or can get it if you want it; that you can change the software and use pieces of it in new free programs; and that you are informed that you can do these things. To protect your rights, we need to make restrictions that forbid distributors to deny you these rights or to ask you to surrender these rights. These restrictions translate to certain responsibilities for you if you distribute copies of the library or if you modify it. For example, if you distribute copies of the library, whether gratis or for a fee, you must give the recipients all the rights that we gave you. You must make sure that they, too, receive or can get the source code. If you link other code with the library, you must provide complete object files to the recipients, so that they can relink them with the library after making changes to the library and recompiling it. And you must show them these terms so they know their rights. We protect your rights with a two-step method: (1) we copyright the library, and (2) we offer you this license, which gives you legal permission to copy, distribute and/or modify the library. To protect each distributor, we want to make it very clear that there is no warranty for the free library. Also, if the library is modified by someone else and passed on, the recipients should know that what they have is not the original version, so that the original author's reputation will not be affected by problems that might be introduced by others. Finally, software patents pose a constant threat to the existence of any free program. We wish to make sure that a company cannot effectively restrict the users of a free program by obtaining a restrictive license from a patent holder. Therefore, we insist that any patent license obtained for a version of the library must be consistent with the full freedom of use specified in this license. Most GNU software, including some libraries, is covered by the ordinary GNU General Public License. This license, the GNU Lesser General Public License, applies to certain designated libraries, and is quite different from the ordinary General Public License. We use this license for certain libraries in order to permit linking those libraries into non-free programs. When a program is linked with a library, whether statically or using a shared library, the combination of the two is legally speaking a combined work, a derivative of the original library. The ordinary General Public License therefore permits such linking only if the entire combination fits its criteria of freedom. The Lesser General Public License permits more lax criteria for linking other code with the library. We call this license the "Lesser" General Public License because it does Less to protect the user's freedom than the ordinary General Public License. It also provides other free software developers Less of an advantage over competing non-free programs. These disadvantages are the reason we use the ordinary General Public License for many libraries. However, the Lesser license provides advantages in certain special circumstances. For example, on rare occasions, there may be a special need to encourage the widest possible use of a certain library, so that it becomes a de-facto standard. To achieve this, non-free programs must be allowed to use the library. A more frequent case is that a free library does the same job as widely used non-free libraries. In this case, there is little to gain by limiting the free library to free software only, so we use the Lesser General Public License. In other cases, permission to use a particular library in non-free programs enables a greater number of people to use a large body of free software. For example, permission to use the GNU C Library in non-free programs enables many more people to use the whole GNU operating system, as well as its variant, the GNU/Linux operating system. Although the Lesser General Public License is Less protective of the users' freedom, it does ensure that the user of a program that is linked with the Library has the freedom and the wherewithal to run that program using a modified version of the Library. The precise terms and conditions for copying, distribution and modification follow. Pay close attention to the difference between a "work based on the library" and a "work that uses the library". The former contains code derived from the library, whereas the latter must be combined with the library in order to run. GNU LESSER GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License Agreement applies to any software library or other program which contains a notice placed by the copyright holder or other authorized party saying it may be distributed under the terms of this Lesser General Public License (also called "this License"). Each licensee is addressed as "you". A "library" means a collection of software functions and/or data prepared so as to be conveniently linked with application programs (which use some of those functions and data) to form executables. The "Library", below, refers to any such software library or work which has been distributed under these terms. A "work based on the Library" means either the Library or any derivative work under copyright law: that is to say, a work containing the Library or a portion of it, either verbatim or with modifications and/or translated straightforwardly into another language. (Hereinafter, translation is included without limitation in the term "modification".) "Source code" for a work means the preferred form of the work for making modifications to it. For a library, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the library. Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running a program using the Library is not restricted, and output from such a program is covered only if its contents constitute a work based on the Library (independent of the use of the Library in a tool for writing it). Whether that is true depends on what the Library does and what the program that uses the Library does. 1. You may copy and distribute verbatim copies of the Library's complete source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and distribute a copy of this License along with the Library. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Library or any portion of it, thus forming a work based on the Library, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) The modified work must itself be a software library. b) You must cause the files modified to carry prominent notices stating that you changed the files and the date of any change. c) You must cause the whole of the work to be licensed at no charge to all third parties under the terms of this License. d) If a facility in the modified Library refers to a function or a table of data to be supplied by an application program that uses the facility, other than as an argument passed when the facility is invoked, then you must make a good faith effort to ensure that, in the event an application does not supply such function or table, the facility still operates, and performs whatever part of its purpose remains meaningful. (For example, a function in a library to compute square roots has a purpose that is entirely well-defined independent of the application. Therefore, Subsection 2d requires that any application-supplied function or table used by this function must be optional: if the application does not supply it, the square root function must still compute square roots.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Library, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Library, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Library. In addition, mere aggregation of another work not based on the Library with the Library (or with a work based on the Library) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may opt to apply the terms of the ordinary GNU General Public License instead of this License to a given copy of the Library. To do this, you must alter all the notices that refer to this License, so that they refer to the ordinary GNU General Public License, version 2, instead of to this License. (If a newer version than version 2 of the ordinary GNU General Public License has appeared, then you can specify that version instead if you wish.) Do not make any other change in these notices. Once this change is made in a given copy, it is irreversible for that copy, so the ordinary GNU General Public License applies to all subsequent copies and derivative works made from that copy. This option is useful when you wish to copy part of the code of the Library into a program that is not a library. 4. You may copy and distribute the Library (or a portion or derivative of it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange. If distribution of object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place satisfies the requirement to distribute the source code, even though third parties are not compelled to copy the source along with the object code. 5. A program that contains no derivative of any portion of the Library, but is designed to work with the Library by being compiled or linked with it, is called a "work that uses the Library". Such a work, in isolation, is not a derivative work of the Library, and therefore falls outside the scope of this License. However, linking a "work that uses the Library" with the Library creates an executable that is a derivative of the Library (because it contains portions of the Library), rather than a "work that uses the library". The executable is therefore covered by this License. Section 6 states terms for distribution of such executables. When a "work that uses the Library" uses material from a header file that is part of the Library, the object code for the work may be a derivative work of the Library even though the source code is not. Whether this is true is especially significant if the work can be linked without the Library, or if the work is itself a library. The threshold for this to be true is not precisely defined by law. If such an object file uses only numerical parameters, data structure layouts and accessors, and small macros and small inline functions (ten lines or less in length), then the use of the object file is unrestricted, regardless of whether it is legally a derivative work. (Executables containing this object code plus portions of the Library will still fall under Section 6.) Otherwise, if the work is a derivative of the Library, you may distribute the object code for the work under the terms of Section 6. Any executables containing that work also fall under Section 6, whether or not they are linked directly with the Library itself. 6. As an exception to the Sections above, you may also combine or link a "work that uses the Library" with the Library to produce a work containing portions of the Library, and distribute that work under terms of your choice, provided that the terms permit modification of the work for the customer's own use and reverse engineering for debugging such modifications. You must give prominent notice with each copy of the work that the Library is used in it and that the Library and its use are covered by this License. You must supply a copy of this License. If the work during execution displays copyright notices, you must include the copyright notice for the Library among them, as well as a reference directing the user to the copy of this License. Also, you must do one of these things: a) Accompany the work with the complete corresponding machine-readable source code for the Library including whatever changes were used in the work (which must be distributed under Sections 1 and 2 above); and, if the work is an executable linked with the Library, with the complete machine-readable "work that uses the Library", as object code and/or source code, so that the user can modify the Library and then relink to produce a modified executable containing the modified Library. (It is understood that the user who changes the contents of definitions files in the Library will not necessarily be able to recompile the application to use the modified definitions.) b) Use a suitable shared library mechanism for linking with the Library. A suitable mechanism is one that (1) uses at run time a copy of the library already present on the user's computer system, rather than copying library functions into the executable, and (2) will operate properly with a modified version of the library, if the user installs one, as long as the modified version is interface-compatible with the version that the work was made with. c) Accompany the work with a written offer, valid for at least three years, to give the same user the materials specified in Subsection 6a, above, for a charge no more than the cost of performing this distribution. d) If distribution of the work is made by offering access to copy from a designated place, offer equivalent access to copy the above specified materials from the same place. e) Verify that the user has already received a copy of these materials or that you have already sent this user a copy. For an executable, the required form of the "work that uses the Library" must include any data and utility programs needed for reproducing the executable from it. However, as a special exception, the materials to be distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. It may happen that this requirement contradicts the license restrictions of other proprietary libraries that do not normally accompany the operating system. Such a contradiction means you cannot use both them and the Library together in an executable that you distribute. 7. You may place library facilities that are a work based on the Library side-by-side in a single library together with other library facilities not covered by this License, and distribute such a combined library, provided that the separate distribution of the work based on the Library and of the other library facilities is otherwise permitted, and provided that you do these two things: a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities. This must be distributed under the terms of the Sections above. b) Give prominent notice with the combined library of the fact that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work. 8. You may not copy, modify, sublicense, link with, or distribute the Library except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense, link with, or distribute the Library is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 9. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Library or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Library (or any work based on the Library), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Library or works based on it. 10. Each time you redistribute the Library (or any work based on the Library), the recipient automatically receives a license from the original licensor to copy, distribute, link with or modify the Library subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties with this License. 11. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Library at all. For example, if a patent license would not permit royalty-free redistribution of the Library by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Library. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply, and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 12. If the distribution and/or use of the Library is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Library under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 13. The Free Software Foundation may publish revised and/or new versions of the Lesser General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Library specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Library does not specify a license version number, you may choose any version ever published by the Free Software Foundation. 14. If you wish to incorporate parts of the Library into other free programs whose distribution conditions are incompatible with these, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Libraries If you develop a new library, and you want it to be of the greatest possible use to the public, we recommend making it free software that everyone can redistribute and change. You can do so by permitting redistribution under these terms (or, alternatively, under the terms of the ordinary General Public License). To apply these terms, attach the following notices to the library. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Also add information on how to contact you by electronic and paper mail. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the library, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the library `Frob' (a library for tweaking knobs) written by James Random Hacker. , 1 April 1990 Ty Coon, President of Vice That's all there is to it! crashmail-0.71/src/jamlib/jam.h0100644000000000000000000002533410073762726015071 0ustar rootroot/* JAMLIB - A JAM subroutine library Copyright (C) 1999 Björn Stenberg This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Changes made by Johan Billing 2000-04-16: - Added #defines for JAM_NO_MESSAGE and JAM_CORRUPT_MSG - Added #ifndef linux around typedefs for ushort and ulong - Added prototype for JAM_AddEmptyMessage() Backported changes from JAMLIB 1.4.7 made by Johan Billing 2003-10-26 - Added prototype for JAM_DeleteMessage() */ /*********************************************************************** ** ** JAM Definitions ** ***********************************************************************/ #ifndef __JAM_H__ #define __JAM_H__ #include #include #include #ifndef linux typedef unsigned short ushort; /* must be 16 bits wide */ typedef unsigned long ulong; /* must be 32 bits wide */ #endif typedef unsigned char uchar; /* must be 8 bits wide */ /* ** Error codes */ #define JAM_BAD_PARAM 1 /* one or more parameters are wrong */ #define JAM_IO_ERROR 2 /* i/o error. check JAM_Errno() for details */ #define JAM_LOCK_FAILED 3 /* lock could not be set */ #define JAM_NOT_LOCKED 4 /* the message base was not locked before writing */ #define JAM_NO_MEMORY 5 /* out of memory! */ #define JAM_NO_USER 6 /* user not found */ #define JAM_NO_MESSAGE 7 /* message has been deleted */ #define JAM_CORRUPT_MSG 8 /* message header is corrupt */ /* ** CRC definitions */ #define JAM_NO_CRC 0xffffffff /* ** File extensions */ #define EXT_HDRFILE ".jhr" #define EXT_TXTFILE ".jdt" #define EXT_IDXFILE ".jdx" #define EXT_LRDFILE ".jlr" /* ** Revision level and header signature */ #define CURRENTREVLEV 1 #define HEADERSIGNATURE "JAM\0" /* ** Header file information block, stored first in all .JHR files */ typedef struct { uchar Signature[4]; /* followed by */ ulong DateCreated; /* Creation date */ ulong ModCounter; /* Last processed counter */ ulong ActiveMsgs; /* Number of active (not deleted) msgs */ ulong PasswordCRC; /* CRC-32 of password to access */ ulong BaseMsgNum; /* Lowest message number in index file */ uchar RSRVD[1000]; /* Reserved space */ } s_JamBaseHeader; /* ** Message status bits */ #define MSG_LOCAL 0x00000001L /* Msg created locally */ #define MSG_INTRANSIT 0x00000002L /* Msg is in-transit */ #define MSG_PRIVATE 0x00000004L /* Private */ #define MSG_READ 0x00000008L /* Read by addressee */ #define MSG_SENT 0x00000010L /* Sent to remote */ #define MSG_KILLSENT 0x00000020L /* Kill when sent */ #define MSG_ARCHIVESENT 0x00000040L /* Archive when sent */ #define MSG_HOLD 0x00000080L /* Hold for pick-up */ #define MSG_CRASH 0x00000100L /* Crash */ #define MSG_IMMEDIATE 0x00000200L /* Send Msg now, ignore restrictions */ #define MSG_DIRECT 0x00000400L /* Send directly to destination */ #define MSG_GATE 0x00000800L /* Send via gateway */ #define MSG_FILEREQUEST 0x00001000L /* File request */ #define MSG_FILEATTACH 0x00002000L /* File(s) attached to Msg */ #define MSG_TRUNCFILE 0x00004000L /* Truncate file(s) when sent */ #define MSG_KILLFILE 0x00008000L /* Delete file(s) when sent */ #define MSG_RECEIPTREQ 0x00010000L /* Return receipt requested */ #define MSG_CONFIRMREQ 0x00020000L /* Confirmation receipt requested */ #define MSG_ORPHAN 0x00040000L /* Unknown destination */ #define MSG_ENCRYPT 0x00080000L /* Msg text is encrypted */ #define MSG_COMPRESS 0x00100000L /* Msg text is compressed */ #define MSG_ESCAPED 0x00200000L /* Msg text is seven bit ASCII */ #define MSG_FPU 0x00400000L /* Force pickup */ #define MSG_TYPELOCAL 0x00800000L /* Msg is for local use only (no export) */ #define MSG_TYPEECHO 0x01000000L /* Msg is for conference distribution */ #define MSG_TYPENET 0x02000000L /* Msg is direct network mail */ #define MSG_NODISP 0x20000000L /* Msg may not be displayed to user */ #define MSG_LOCKED 0x40000000L /* Msg is locked, no editing possible */ #define MSG_DELETED 0x80000000L /* Msg is deleted */ /* ** Message header */ typedef struct { uchar Signature[4]; /* followed by */ ushort Revision; /* CURRENTREVLEV */ ushort ReservedWord; /* Reserved */ ulong SubfieldLen; /* Length of Subfields */ ulong TimesRead; /* Number of times message read */ ulong MsgIdCRC; /* CRC-32 of MSGID line */ ulong ReplyCRC; /* CRC-32 of REPLY line */ ulong ReplyTo; /* This msg is a reply to.. */ ulong Reply1st; /* First reply to this msg */ ulong ReplyNext; /* Next msg in reply chain */ ulong DateWritten; /* When msg was written */ ulong DateReceived; /* When msg was received/read */ ulong DateProcessed; /* When msg was processed by packer */ ulong MsgNum; /* Message number (1-based) */ ulong Attribute; /* Msg attribute, see "Status bits" */ ulong Attribute2; /* Reserved for future use */ ulong TxtOffset; /* Offset of text in text file */ ulong TxtLen; /* Length of message text */ ulong PasswordCRC; /* CRC-32 of password to access msg */ ulong Cost; /* Cost of message */ } s_JamMsgHeader; /* ** Message header Subfield types */ #define JAMSFLD_OADDRESS 0 #define JAMSFLD_DADDRESS 1 #define JAMSFLD_SENDERNAME 2 #define JAMSFLD_RECVRNAME 3 #define JAMSFLD_MSGID 4 #define JAMSFLD_REPLYID 5 #define JAMSFLD_SUBJECT 6 #define JAMSFLD_PID 7 #define JAMSFLD_TRACE 8 #define JAMSFLD_ENCLFILE 9 #define JAMSFLD_ENCLFWALIAS 10 #define JAMSFLD_ENCLFREQ 11 #define JAMSFLD_ENCLFILEWC 12 #define JAMSFLD_ENCLINDFILE 13 #define JAMSFLD_EMBINDAT 1000 #define JAMSFLD_FTSKLUDGE 2000 #define JAMSFLD_SEENBY2D 2001 #define JAMSFLD_PATH2D 2002 #define JAMSFLD_FLAGS 2003 #define JAMSFLD_TZUTCINFO 2004 #define JAMSFLD_UNKNOWN 0xffff /* ** Message header Subfield */ typedef struct { ushort LoID; /* Field ID, 0 - 0xffff */ ushort HiID; /* Reserved for future use */ ulong DatLen; /* Length of buffer that follows */ uchar* Buffer; /* DatLen bytes of data */ } s_JamSubfield; typedef struct { ushort LoID; /* Field ID, 0 - 0xffff */ ushort HiID; /* Reserved for future use */ ulong DatLen; /* Length of buffer that follows */ } s_JamSaveSubfield; /* ** Message index record */ typedef struct { ulong UserCRC; /* CRC-32 of destination username */ ulong HdrOffset; /* Offset of header in .JHR file */ } s_JamIndex; /* ** Lastread structure, one per user */ typedef struct { ulong UserCRC; /* CRC-32 of user name (lowercase) */ ulong UserID; /* Unique UserID */ ulong LastReadMsg; /* Last read message number */ ulong HighReadMsg; /* Highest read message number */ } s_JamLastRead; /* ** JAMLIB message base handle */ typedef struct { FILE* HdrFile_PS; /* File handle for .JHR file */ FILE* TxtFile_PS; /* File handle for .JDT file */ FILE* IdxFile_PS; /* File handle for .JDX file */ FILE* LrdFile_PS; /* File handle for .JLR file */ int Errno_I; /* last i/o error */ int Locked_I; /* is area locked? */ ulong LastUserPos_I; /* last position of lastread record */ ulong LastUserId_I; /* userid for the last read lastread record */ } s_JamBase; /* ** JAMLIB subfield packet */ typedef struct { s_JamSubfield** Fields; ulong NumFields; ulong NumAlloc; } s_JamSubPacket; /* ** JAMLIB function declarations */ /* mbase.c */ int JAM_OpenMB ( uchar* Basename_PC, s_JamBase** NewArea_PPS ); int JAM_CloseMB ( s_JamBase* Area_PS ); int JAM_CreateMB ( uchar* Basename_PC, ulong BaseMsg_I, s_JamBase** NewArea_PPS ); int JAM_RemoveMB ( s_JamBase* Area_PS, uchar* Basename_PC ); int JAM_LockMB ( s_JamBase* Area_PS, int Timeout_I ); int JAM_UnlockMB ( s_JamBase* Area_PS ); int JAM_ReadMBHeader ( s_JamBase* Area_PS, s_JamBaseHeader* Header_PS ); int JAM_WriteMBHeader ( s_JamBase* Area_PS, s_JamBaseHeader* Header_PS ); int JAM_FindUser ( s_JamBase* Area_PS, ulong UserCrc_I, ulong StartMsg_I, ulong* MsgNo_PI ); int JAM_GetMBSize ( s_JamBase* Area_PS, ulong* Messages_PI ); /* message.c */ int JAM_ReadMsgHeader ( s_JamBase* Area_PS, ulong MsgNo_I, s_JamMsgHeader* Header_PS, s_JamSubPacket** SubfieldPack_PPS ); int JAM_ReadMsgText ( s_JamBase* Area_PS, ulong Offset_I, ulong Length_I, uchar* Buffer_PC ); int JAM_AddMessage ( s_JamBase* Area_PS, s_JamMsgHeader* Header_PS, s_JamSubPacket* SubPack_PS, uchar* Text_PC, ulong TextLen_I ); int JAM_AddEmptyMessage ( s_JamBase* Area_PS ); int JAM_DeleteMessage ( s_JamBase* Base_PS, ulong MsgNo_I ); int JAM_ChangeMsgHeader ( s_JamBase* Area_PS, ulong MsgNo_I, s_JamMsgHeader* Header_PS ); int JAM_ClearMsgHeader ( s_JamMsgHeader* Header_PS ); int JAM_Errno ( s_JamBase* Area_PS ); /* lastread.c */ int JAM_ReadLastRead ( s_JamBase* Area_PS, ulong User_I, s_JamLastRead* Record_PS ); int JAM_WriteLastRead ( s_JamBase* Area_PS, ulong User_I, s_JamLastRead* Record_PS ); /* subpacket.c */ s_JamSubPacket* JAM_NewSubPacket ( void ); int JAM_DelSubPacket ( s_JamSubPacket* SubPack_PS ); s_JamSubfield* JAM_GetSubfield ( s_JamSubPacket* SubPack_PS ); s_JamSubfield* JAM_GetSubfield_R ( s_JamSubPacket* SubPack_PS , ulong* Count_PI); int JAM_PutSubfield ( s_JamSubPacket* SubPack_PS, s_JamSubfield* Field_PS ); /* crc32.c */ ulong JAM_Crc32 ( uchar* Buffer_PC, ulong Length_I ); #endif crashmail-0.71/src/jamlib/mbase.c0100644000000000000000000003555010073762726015405 0ustar rootroot/* JAMLIB - A JAM subroutine library Copyright (C) 1999 Björn Stenberg This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Changes made by Johan Billing 2000-04-16: - Added support for Win32 and Linux - Changed JAM_OpenMB to open files in binary mode - Changed source to use feof() instead of errno == EPASTEOF - Changed source to use structrw to read and write structures - Fixed broken JAM_FindUser() - #includes string.h and stdlib.h instead of memory.h Backported changes from JAMLIB 1.4.7 made by Johan Billing 2003-10-26 - Now uses calloc instead of malloc/memset - (*NewArea_PPS) will be set to zero even if calloc() failed in JAM_OpenMB() and JAM_CreateMB() - JAM_CreateMB() no longer attempts to forever to lock the newly created messagebase. If the first attempt fails, it will return an error. - jam_Lock() now sets Base_PS->Errno under Linux Other changes made by Johan Billing 2003-10-26 - Fixed comparison between signed and unsigned variable in JAM_GetMBSize() - JAM_CreateMB() would not unlock and close the newly created messagebase upon failure. Changes made by Johan Billing 2004-07-10 - Updated the Win32-specific parts of the code to make it compatible with newer versions of MinGW (tested with 3.1.0-1): * Now uses Sleep() instead of sleep() * Changed _LK_UNLOCK to _LK_UNLCK in jam_Lock() */ /*********************************************************************** ** ** MBASE.C -- Message base handling ** ** Author: Bj”rn Stenberg (bjorn.stenberg@sth.frontec.se) ** ***********************************************************************/ #include #include #include #include #include #include "jam.h" #include "structrw.h" #if defined( __OS2__ ) #include /* ANSI C does not include file locking :-( */ #endif #if defined( __WIN32__ ) #include #include #include #if !defined( _LK_UNLCK ) && defined ( _LK_UNLOCK ) #define _LK_UNLCK _LK_UNLOCK /* For backwards compatibility */ #endif #endif #if defined( __LINUX__ ) #include #include #endif #define OS_ERROR_OFFSET 10000 #if defined( __OS2__ ) #define JAM_Sleep( _x_ ) DosSleep( _x_*1000 ) #endif #if defined( __WIN32__ ) #define JAM_Sleep(x) Sleep(x*1000) #endif #if defined( __LINUX__ ) #define JAM_Sleep(x) sleep(x) #endif /*************************************<********************************** ** ** File-global functions ** ***********************************************************************/ int jam_Open( s_JamBase* Base_PS, uchar* Filename_PC, char* Mode_PC ); int jam_Lock( s_JamBase* Base_PS, int DoLock_I ); /*********************************************************************** ** ** JAM_OpenMB - Open message base ** ***********************************************************************/ int JAM_OpenMB( uchar* Basename_PC, s_JamBase** NewArea_PPS ) { s_JamBase* Base_PS; int Status_I; if ( !NewArea_PPS ) return JAM_BAD_PARAM; *NewArea_PPS = NULL; Base_PS = (s_JamBase*) calloc( 1, sizeof( s_JamBase ) ); if (!Base_PS) return JAM_NO_MEMORY; *NewArea_PPS = Base_PS; Status_I = jam_Open( Base_PS, Basename_PC, "r+b" ); if ( Status_I ) { return Status_I; } return 0; } /*********************************************************************** ** ** JAM_CreateMB - Create a new message base ** ***********************************************************************/ int JAM_CreateMB( uchar* Basename_PC, ulong BaseMsg_I, s_JamBase** NewArea_PPS ) { s_JamBaseHeader Base_S; int Status_I; s_JamBase* Base_PS; if ( !NewArea_PPS || !BaseMsg_I ) return JAM_BAD_PARAM; *NewArea_PPS = NULL; Base_PS = (s_JamBase*) calloc( 1, sizeof( s_JamBase ) ); if (!Base_PS) return JAM_NO_MEMORY; *NewArea_PPS = Base_PS; Status_I = jam_Open( Base_PS, Basename_PC, "w+b" ); if ( Status_I ) return Status_I; Base_S.DateCreated = time(NULL); Base_S.ModCounter = 0; Base_S.ActiveMsgs = 0; Base_S.PasswordCRC = 0xffffffff; Base_S.BaseMsgNum = BaseMsg_I; memset( &Base_S.RSRVD, 0, sizeof( Base_S.RSRVD ) ); Status_I = JAM_LockMB( Base_PS, 0 ); /* If the new base cannot be locked directly, something is seriously wrong */ if ( Status_I ) { JAM_CloseMB(Base_PS); return Status_I; } Status_I = JAM_WriteMBHeader( Base_PS, &Base_S ); if ( Status_I ) { JAM_UnlockMB( Base_PS ); JAM_CloseMB(Base_PS); return Status_I; } JAM_UnlockMB( Base_PS ); return 0; } /*********************************************************************** ** ** JAM_CloseMB - Close message base ** ***********************************************************************/ int JAM_CloseMB( s_JamBase* Base_PS ) { if ( Base_PS->Locked_I ) { int Status_I = JAM_UnlockMB( Base_PS ); if ( Status_I ) return Status_I; } if ( Base_PS->HdrFile_PS ) { fclose( Base_PS->HdrFile_PS ); Base_PS->HdrFile_PS = NULL; fclose( Base_PS->TxtFile_PS ); Base_PS->TxtFile_PS = NULL; fclose( Base_PS->IdxFile_PS ); Base_PS->IdxFile_PS = NULL; fclose( Base_PS->LrdFile_PS ); Base_PS->LrdFile_PS = NULL; } Base_PS->Locked_I = 0; return 0; } /*********************************************************************** ** ** JAM_RemoveMB - Remove a message base ** ***********************************************************************/ int JAM_RemoveMB( s_JamBase* Base_PS, uchar* Basename_PC ) { uchar Filename_AC[250]; int Status_AI[4]; /* .JHR file */ sprintf( Filename_AC, "%s%s", Basename_PC, EXT_HDRFILE ); Status_AI[0] = remove( Filename_AC ); if ( Status_AI[0] ) Base_PS->Errno_I = errno; /* .JDT file */ sprintf( Filename_AC, "%s%s", Basename_PC, EXT_TXTFILE ); Status_AI[1] = remove( Filename_AC ); if ( Status_AI[1] ) Base_PS->Errno_I = errno; /* .JDX file */ sprintf( Filename_AC, "%s%s", Basename_PC, EXT_IDXFILE ); Status_AI[2] = remove( Filename_AC ); if ( Status_AI[2] ) Base_PS->Errno_I = errno; /* .JLR file */ sprintf( Filename_AC, "%s%s", Basename_PC, EXT_LRDFILE ); Status_AI[3] = remove( Filename_AC ); if ( Status_AI[3] ) Base_PS->Errno_I = errno; if (Status_AI[0] || Status_AI[1] || Status_AI[2] || Status_AI[3]) return JAM_IO_ERROR; return 0; } /*********************************************************************** ** ** JAM_GetMBSize - Get the number of messages in message base ** ***********************************************************************/ int JAM_GetMBSize( s_JamBase* Base_PS, ulong* Messages_PI ) { long Offset_I; /* go to end of index file */ if ( fseek( Base_PS->IdxFile_PS, 0, SEEK_END ) ) { Base_PS->Errno_I = errno; return JAM_IO_ERROR; } Offset_I = ftell( Base_PS->IdxFile_PS ); if ( Offset_I == -1 ) { Base_PS->Errno_I = errno; return JAM_IO_ERROR; } *Messages_PI = Offset_I / sizeof( s_JamIndex ); return 0; } /*********************************************************************** ** ** JAM_LockMB - Lock message base ** ***********************************************************************/ int JAM_LockMB( s_JamBase* Base_PS, int Timeout_I ) { if ( Base_PS->Locked_I ) return 0; switch ( Timeout_I ) { /* unlimited timeout */ case -1: while ( jam_Lock( Base_PS, 1 ) == JAM_LOCK_FAILED ) JAM_Sleep( 1 ); return 0; /* no timeout */ case 0: return jam_Lock( Base_PS, 1 ); /* X seconds timeout */ default: { time_t Time_I = time(NULL) + Timeout_I; while ( time(NULL) < Time_I ) { int Result_I; Result_I = jam_Lock( Base_PS, 1 ); if ( Result_I == JAM_LOCK_FAILED ) JAM_Sleep( 1 ); else return Result_I; } return JAM_LOCK_FAILED; } } } /*********************************************************************** ** ** JAM_UnlockMB - Flush all writes and unlock message base ** ***********************************************************************/ int JAM_UnlockMB( s_JamBase* Base_PS ) { fflush( Base_PS->HdrFile_PS ); fflush( Base_PS->TxtFile_PS ); fflush( Base_PS->IdxFile_PS ); fflush( Base_PS->LrdFile_PS ); return jam_Lock( Base_PS, 0 ); } /*********************************************************************** ** ** JAM_ReadMBHeader - Read message base header ** ***********************************************************************/ int JAM_ReadMBHeader( s_JamBase* Base_PS, s_JamBaseHeader* Header_PS ) { if ( !Header_PS || !Base_PS ) return JAM_BAD_PARAM; if ( fseek( Base_PS->HdrFile_PS, 0, SEEK_SET ) ) { Base_PS->Errno_I = errno; return JAM_IO_ERROR; } if ( 1 > freadjambaseheader(Base_PS->HdrFile_PS,Header_PS) ) { Base_PS->Errno_I = errno; return JAM_IO_ERROR; } return 0; } /*********************************************************************** ** ** JAM_WriteMBHeader - Write message base header ** ***********************************************************************/ int JAM_WriteMBHeader( s_JamBase* Base_PS, s_JamBaseHeader* Header_PS ) { if ( !Header_PS || !Base_PS ) return JAM_BAD_PARAM; if ( !Base_PS->Locked_I ) return JAM_NOT_LOCKED; if ( fseek( Base_PS->HdrFile_PS, 0, SEEK_SET ) ) { Base_PS->Errno_I = errno; return JAM_IO_ERROR; } /* ensure header looks right */ memcpy( Header_PS->Signature, HEADERSIGNATURE, 4 ); Header_PS->ModCounter++; if ( 1 > fwritejambaseheader(Base_PS->HdrFile_PS,Header_PS) ) { Base_PS->Errno_I = errno; return JAM_IO_ERROR; } fflush( Base_PS->HdrFile_PS ); return 0; } /*********************************************************************** ** ** JAM_FindUser - Scan scan file for messages to a user ** ***********************************************************************/ int JAM_FindUser( s_JamBase* Base_PS, ulong UserCrc_I, ulong StartMsg_I, ulong* MsgNo_PI ) { ulong MsgNo_I; /* go to start message */ if ( fseek( Base_PS->IdxFile_PS, StartMsg_I * sizeof( s_JamIndex ), SEEK_SET ) ) { Base_PS->Errno_I = errno; return JAM_IO_ERROR; } /* scan file */ for ( MsgNo_I = StartMsg_I; ; MsgNo_I++ ) { s_JamIndex Index_S; if ( 1 > freadjamindex(Base_PS->IdxFile_PS,&Index_S) ) { if ( feof(Base_PS->IdxFile_PS) ) return JAM_NO_USER; Base_PS->Errno_I = errno; return JAM_IO_ERROR; } if ( Index_S.UserCRC == UserCrc_I ) break; } *MsgNo_PI = MsgNo_I; return 0; } /*********************************************************************** ** ** jam_Lock - Lock/unlock a message base ** ***********************************************************************/ int jam_Lock( s_JamBase* Base_PS, int DoLock_I ) { #if defined(__OS2__) FILELOCK Area_S; APIRET Status_I; ULONG Timeout_I = 0; int Handle_I; Handle_I = fileno( Base_PS->HdrFile_PS ); if ( Handle_I == -1 ) { Base_PS->Errno_I = errno; return JAM_IO_ERROR; } Area_S.lOffset = 0; Area_S.lRange = 1; if ( DoLock_I ) Status_I = DosSetFileLocks( Handle_I, NULL, &Area_S, Timeout_I, 0 ); else Status_I = DosSetFileLocks( Handle_I, &Area_S, NULL, Timeout_I, 0 ); if ( Status_I ) { if ( 232 == Status_I ) return JAM_LOCK_FAILED; Base_PS->Errno_I = Status_I + OS_ERROR_OFFSET; return JAM_IO_ERROR; } if ( DoLock_I ) Base_PS->Locked_I = 1; else Base_PS->Locked_I = 0; return 0; #elif defined(__WIN32__) int Handle_I,Status_I; fseek(Base_PS->HdrFile_PS,0,SEEK_SET); /* Lock from start of file */ Handle_I = fileno( Base_PS->HdrFile_PS ); if ( Handle_I == -1 ) { Base_PS->Errno_I = errno; return JAM_IO_ERROR; } if ( DoLock_I ) Status_I = _locking(Handle_I,_LK_NBLCK,1); else Status_I = _locking(Handle_I,_LK_UNLCK,1); if ( Status_I ) return JAM_LOCK_FAILED; if ( DoLock_I ) Base_PS->Locked_I = 1; else Base_PS->Locked_I = 0; return 0; #elif defined(__LINUX__) int Handle_I,Status_I; struct flock fl; fseek(Base_PS->HdrFile_PS,0,SEEK_SET); /* Lock from start of file */ Handle_I = fileno( Base_PS->HdrFile_PS ); if ( Handle_I == -1 ) { Base_PS->Errno_I = errno; return JAM_IO_ERROR; } if(DoLock_I) fl.l_type=F_WRLCK; else fl.l_type=F_UNLCK; fl.l_whence=SEEK_SET; fl.l_start=0; fl.l_len=1; fl.l_pid=getpid(); Status_I=fcntl(Handle_I,F_SETLK,&fl); if ( Status_I ) { Base_PS->Errno_I = errno; return JAM_LOCK_FAILED; } if ( DoLock_I ) Base_PS->Locked_I = 1; else Base_PS->Locked_I = 0; return 0; #else #error Unsupported platform #endif } /*********************************************************************** ** ** jam_Open - Open/create message base files ** ***********************************************************************/ int jam_Open( s_JamBase* Base_PS, uchar* Basename_PC, char* Mode_PC ) { uchar Filename_AC[250]; /* .JHR file */ sprintf( Filename_AC, "%s%s", Basename_PC, EXT_HDRFILE ); Base_PS->HdrFile_PS = fopen( Filename_AC, Mode_PC ); if (!Base_PS->HdrFile_PS) { Base_PS->Errno_I = errno; return JAM_IO_ERROR; } /* .JDT file */ sprintf( Filename_AC, "%s%s", Basename_PC, EXT_TXTFILE ); Base_PS->TxtFile_PS = fopen( Filename_AC, Mode_PC ); if (!Base_PS->TxtFile_PS) { Base_PS->Errno_I = errno; fclose( Base_PS->HdrFile_PS ); Base_PS->HdrFile_PS = NULL; return JAM_IO_ERROR; } /* .JDX file */ sprintf( Filename_AC, "%s%s", Basename_PC, EXT_IDXFILE ); Base_PS->IdxFile_PS = fopen( Filename_AC, Mode_PC ); if (!Base_PS->IdxFile_PS) { Base_PS->Errno_I = errno; fclose( Base_PS->HdrFile_PS ); Base_PS->HdrFile_PS = NULL; fclose( Base_PS->TxtFile_PS ); Base_PS->TxtFile_PS = NULL; return JAM_IO_ERROR; } /* .JLR file */ sprintf( Filename_AC, "%s%s", Basename_PC, EXT_LRDFILE ); Base_PS->LrdFile_PS = fopen( Filename_AC, Mode_PC ); if (!Base_PS->LrdFile_PS) { Base_PS->Errno_I = errno; fclose( Base_PS->HdrFile_PS ); Base_PS->HdrFile_PS = NULL; fclose( Base_PS->TxtFile_PS ); Base_PS->TxtFile_PS = NULL; fclose( Base_PS->IdxFile_PS ); Base_PS->IdxFile_PS = NULL; return JAM_IO_ERROR; } return 0; } crashmail-0.71/src/jamlib/subpack.c0100644000000000000000000001305710073762726015744 0ustar rootroot/* JAMLIB - A JAM subroutine library Copyright (C) 1999 Björn Stenberg This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Changes made by Johan Billing 2000-04-16: - Fixed broken JAM_GetSubfield() - #includes stdlib.h instead of malloc.h and memory.h Changes made by Johan Billing 2000-09-17: - Added JAM_GetSubfield_R() Backported changes from JAMLIB 1.4.7 made by Johan Billing 2003-10-22 - JAM_NewSubPacket() and JAM_PutSubField() would give memory leaks under low memory conditions. Fixed. Other changes made by Johan Billing 2003-10-22 - Fixed comparison between signed and unsigned variable in JAM_DelSubPacket() and JAM_GetSubField() */ /*********************************************************************** ** ** SUBPACKET.C -- Subfield packet handling ** ** Author: Bj”rn Stenberg (bjorn.stenberg@sth.frontec.se) ** ***********************************************************************/ #include #include #include #include #include "jam.h" /*********************************************************************** ** ** JAM_NewSubPacket - Create a new subfield packet ** ***********************************************************************/ s_JamSubPacket* JAM_NewSubPacket( void ) { s_JamSubPacket* Sub_PS; /* allocate packet struct */ Sub_PS = (s_JamSubPacket*) malloc( sizeof( s_JamSubPacket ) ); if ( !Sub_PS ) return NULL; Sub_PS->NumAlloc = 20; Sub_PS->NumFields = 0; /* allocate pointer array */ Sub_PS->Fields = (s_JamSubfield**) calloc( Sub_PS->NumAlloc, sizeof( s_JamSubfield* ) ); if ( !Sub_PS->Fields ) { free (Sub_PS); return NULL; } return Sub_PS; } /*********************************************************************** ** ** JAM_DelSubPacket - Free the data associated with a subfield packet ** ***********************************************************************/ int JAM_DelSubPacket( s_JamSubPacket* SubPack_PS ) { ulong i; if (!SubPack_PS) return JAM_BAD_PARAM; for ( i=0; i < SubPack_PS->NumFields; i++ ) { s_JamSubfield* Field_PS = SubPack_PS->Fields[i]; if ( Field_PS->Buffer ) free( Field_PS->Buffer ); free( Field_PS ); } free( SubPack_PS->Fields ); free( SubPack_PS ); return 0; } /*********************************************************************** ** ** JAM_GetSubfield -- Get first/next subfield from a subfield packet ** (not reentrant) ** ***********************************************************************/ s_JamSubfield* JAM_GetSubfield( s_JamSubPacket* SubPack_PS ) { static s_JamSubPacket* LastPack_PS = NULL; static ulong NextIndex_I = 0; if ( SubPack_PS ) { LastPack_PS = SubPack_PS; NextIndex_I = 0; } if ( NextIndex_I < LastPack_PS->NumFields ) return LastPack_PS->Fields[ NextIndex_I++ ]; return NULL; } /*********************************************************************** ** ** JAM_GetSubfield_R -- Get first/next subfield from a subfield packet ** (reentrant) ** ***********************************************************************/ s_JamSubfield* JAM_GetSubfield_R( s_JamSubPacket* SubPack_PS , ulong* Count_PI) { if ( *Count_PI < SubPack_PS->NumFields ) return SubPack_PS->Fields[ (*Count_PI)++ ]; return NULL; } /*********************************************************************** ** ** JAM_PutSubfield -- Add a subfield to a subfield packet ** ***********************************************************************/ int JAM_PutSubfield( s_JamSubPacket* SubPack_PS, s_JamSubfield* Field_PS ) { s_JamSubfield* NewField_PS; uchar* NewBuf_PC; /* do we have to expand the array? */ if ( SubPack_PS->NumFields == SubPack_PS->NumAlloc ) { s_JamSubfield** Fields_PPS; SubPack_PS->NumAlloc *= 2; Fields_PPS = (s_JamSubfield**) realloc( SubPack_PS->Fields, SubPack_PS->NumAlloc * sizeof( s_JamSubfield* ) ); if ( !Fields_PPS ) return JAM_NO_MEMORY; SubPack_PS->Fields=Fields_PPS; } /* ** Copy the passed subfield */ /* allocate a new subfield */ NewField_PS = (s_JamSubfield*) malloc( sizeof( s_JamSubfield ) ); if ( !NewField_PS ) return JAM_NO_MEMORY; /* allocate a new buffer */ if ( Field_PS->DatLen ) { NewBuf_PC = (uchar*) malloc( Field_PS->DatLen ); if ( !NewBuf_PC ) { free (NewField_PS); return JAM_NO_MEMORY; } memcpy( NewBuf_PC, Field_PS->Buffer, Field_PS->DatLen ); } else NewBuf_PC = NULL; /* copy field struct */ NewField_PS->LoID = Field_PS->LoID; NewField_PS->HiID = Field_PS->HiID; NewField_PS->DatLen = Field_PS->DatLen; NewField_PS->Buffer = NewBuf_PC; /* ** Update subfield packet */ SubPack_PS->Fields[ SubPack_PS->NumFields ] = NewField_PS; SubPack_PS->NumFields++; return 0; } crashmail-0.71/src/jamlib/jamlib.doc0100644000000000000000000012704710073762726016102 0ustar rootroot JAMLIB A JAM subroutine library by Björn Stenberg modifications by Johan Billing version 1.3.2 2004-07-10 GENERAL ======= History ------- JAMLIB 1.0 was originally released by Björn Stenberg 1996-03-06. Since the original license did not permit modification of the library, Johan Billing contacted Björn Stenberg and asked him to change the license. Björn Stenberg agreed to change the license to the GNU Lesser General Public License 1999-12-21 (see the accompanying file LICENSE). After that, some minor additions and bug fixes were made by Johan Billing and JAMLIB 1.1 was released under the new license. Changes in 1.3.2: * Updated the Win32-specific parts of the code to make it compatible with newer versions of MinGW (tested with 3.1.0-1). Changes in 1.3.1: * Backported the following bugfixes and improvements from JAMLIB 1.4.7 while retaining the platform-independence and high portability of the early versions of JAMLIB. - JAMLIB now uses calloc() instead of malloc() followed by memset() - JAM_OpenMB() and JAM_CreateMB() will set (*NewArea_PPS) to NULL if calloc() failed - JAM_CreateMB() no longer attempts indefinitely to lock the newly created messagebase. If the first attempt fails, it will return an error. - jam_Lock() now sets Base_PS->Errno under Linux - JAM_NewSubPacket() and JAM_PutSubField() would give memory leaks under conditions of low memory conditions. Fixed. - JAM_ReadMsgHeader() would give memory leaks on failure. Fixed. - Added JAM_DeleteMessage() Big thanks to Sir Raorn (and others?) for finding and fixing these bugs! * JAM_CreateMB() would never unlock or close the newly created messagebase upon failure. Fixed. * Improved handling of ActiveMsgs counter. JAM_AddMessage() now only increases ActiveMsgs if the added message does not have MSG_DELETED set. JAM_ChangeMsgHeader() decreases ActiveMsgs if MSG_DELETED is set and the message wasn't already deleted. JAM_DeleteMessage() now only decreases ActiveMsgs if the message wasn't already deleted. * Updated the documentation to reflect the need to free() memory after JAM_CloseMB() and failed calls to JAM_OpenMB() and JAM_CreateMB(). * Eliminated compiler warnings Changes in 1.3: * JAM_AddMessage() would fail when trying to add an empty message to the messagebase under Linux. Fixed. Changes in 1.2: * Since JAM_GetSubField() is not reentrant and cannot be used in multi-threaded applications, JAM_GetSubField_R() was added as a replacement for cases where a reentrant function is needed. Changes in 1.1: * Added support for Win32 and Linux * Added JAM_AddEmptyMessage() * Rewrote the Makefiles * Rewrote the CRC32 routine * Fixed broken JAM_FindUser() * Fixed broken JAM_GetSubfield() * Changed JAM_OpenMB so that files are opened in binary mode. This is necessary to use JAMLIB under Windows. * Improved JAM_ReadMsgHeader() to give the error JAM_NO_MESSAGE if the message no longer exists in the messagebase and JAM_CORRUPT_MSG if the subfields of the message have been corrupted. * Improved portability by changing JAMLIB so that it no longer reads and writes stuctures directly using fread() and fwrite(). * Improved ANSI-C compatibilty by no longer including the non-ANSI header file memory.h and using feof() to check for EOF instead of errno == EPASTEOF. * Added an #ifdef so that ushort and ulong are no longer defined in jam.h when compiling under Linux. These are normally already defined in the standard header files. License ------- JAMLIB - A JAM subroutine library Copyright (C) 1999 Björn Stenberg This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Description ----------- These are a collection of subroutines that encapsulate much of the format-specific and tedious details of the JAM message base format. The idea is that application programmers by using these routines can concentrate on the more high-level issues of their programs instead of worrying about their JAM routines. I [Björn Stenberg] wrote these routines primarily because I needed them myself. I was trying to implement JAM support in my FrexxLink BBS system and was frustrated by the poor level of documentation supplied in the JAMAPI archive distributed by the JAM authors. Finally, I dove into the JAMAPI source code in a desperate attempt at finding out how to use it. To my despair, I discovered that the JAMAPI is targeted at a very low level. I would need to implement a lot of JAM-handling code into my own program. This library is an attempt to do two things: Firstly, provide an, at least sparingly, _documented_ API, allowing application programmers to easily implement JAM into their programs. Secondly, raise the level of functionality above that of the original JAMAPI package, so that the application programmer does not have to learn and understand all the internals of the JAM message base format to implement support for it. I have not succeded completely on any of the two points, of course. Documentation can never be too good, and there are still a few things about JAM you must know in order to use it. But I think I have made it somewhat easier than perhaps was the case before. References ---------- If you are extra curious about the JAM message format, I suggest you get a hold of an archive called JAMAPI.ARJ. That archive contains a file called JAM.DOC which is the file I have used as reference for the development of these routines. Credits ------- All original code except for the CRC32 routine was written by Björn Stenberg. The CRC32 code was rewritten by Johan Billing for JAMLIB 1.1 to replace the original CRC32 code whose origin and copyright was unclear. The jam.h header file is a compilation of the best from the various header files in the JAMAPI package with some of additions by Björn Stenberg as well. Additions and modifications by Johan Billing. The JAM message base proposal is: JAM(mbp) - Copyright 1993 Joaquim Homrighausen, Andrew Milner, Mats Birch, Mats Wallin. ALL RIGHTS RESERVED Contact Information ------------------- For questions about JAMLIB, please contact: Johan Billing E-mail: billing@df.lth.se If you wish to contact Björn Stenberg, his current e-mail address (as of 1999-12-21) is bjorn@haxx.nu. THE LIBRARY =========== The Source Code --------------- I made a point of making this library as system independant as I could. Only one function needs to be altered when porting this to another system: The file locking. ANSI C does not include file locking so there is not much I can do about it. The choice of C over C++ is a part of this philosophy aswell. More systems have C compilers than C++ compilers, and more people know C than C++. Also, converting this library to a C++ class should be fairly simple. If you do, send me a copy. I use some naming conventions throughout the code and in the examples. These are invented by myself as a reaction to the stunningly ugly and hard-to-read Hungarian Notation promoted by some people. The rules of my notation are simple: * All library-global identifiers are prefixed with 'JAM_'. All file-global identifiers are prefixed with 'jam_'. Local identifiers do not have prefixes. * All variables have a suffix describing their basic type. Suffixes used in this library are: _I - integer (int Example_I) _C - character (char Example_C) _S - struct (struct Example_S) _P - pointer (void* Example_P) _A - array Suffixes are then combined, to show the correct type: _PI - pointer to integer (int* Example_PI) _PC - pointer to char (char* Example_PC) _AC - array of char (char Example_AC[x]) _PPS - pointer to pointer to struct (struct** Example_PPS) * Functions do not have suffixes The whole idea is that it is quicker to read and comprehend a variable called 'Text_PC' than one called 'pszText'. We read from left to right, and thus the most important information - the name - should be the leftmost data in the word. The variable type is additional information and is therefore added to the end where it does not disturb the reader. The Functions ------------- The library is divided into five groups: * Message base functions * Message functions * Subfield functions * LastRead functions * Miscellanous functions -------------------------------------------------------------------------- Message base functions ---------------------- These functions handle JAM message bases, by opening, locking, scanning etc the contents of a message base. These are fairly straight-forward and simple routines that you should have little, if any, trouble with. A message base is identified by a message base handle, which is obtained from either JAM_OpenMB() och JAM_CreateMB(). All functions that read or write from the message base take this handle as parameter, to know which message base to use. ================================ JAM_OpenMB - Open a message base ================================ Syntax int JAM_OpenMB( uchar* Basename_PC, t_JamBase** NewBase_PPS ); Description Opens a message base. Only one message base can be open at a time. Parameters Basename_PC The path and base filename of the message base. "Base filename" means the filename without the JAM-specific extension. NewBase_PPS A pointer to a message base handle where the new message base handle will be written. On error you must free() this memory if (*NewBase_PPS) not NULL. Returns 0 if successful JAM_IO_ERROR if an I/O error occured. see JAM_Errno() JAM_BAD_PARAM if NewBas_PPS is NULL Example { int Result_I; Result_I = JAM_OpenMB( "c:\\jam\\mybase", &Base_PS ); if ( Result_I ) printf("JAM_OpenMB returned %d.\n", Result_I ); } ================================ JAM_CloseMB - Close message base ================================ Syntax int JAM_CloseMB( Base_PS ); Description Unlocks (if locked) and closes the currently open message base. Parameters Base_PS The message base to close. Note, that you must free() this memory by yourself. Returns 0 if successful JAM_IO_ERROR if an I/O error occured. see JAM_Errno() JAM_LOCK_FAILED if the message base could not be unlocked Example { int Result_I; Result_I = JAM_CloseMB( Base_PS ); if ( Result_I ) printf("JAM_CloseMB returned %d.\n", Result_I ); } ======================================== JAM_CreateMB - Create a new message base ======================================== Syntax int JAM_CreateMB( uchar* Basename_PC, ulong BaseMsg_I, s_JamBase** NewBase_PPS ); Description Creates the necessary files for a new message base and writes a new message base header. If the message base already exists, its contents are destroyed. Parameters Basename_PC The path and base filename of the new message base. BaseMsg_I The base message number (first message #) for the new message base. This number is used when calculating new messages' unique message number. It should not be set to 0. NewBase_PPS A pointer to a message base handle where the new message base handle will be written. On error you must free() this memory if (*NewBase_PPS) not NULL. Returns 0 if successful JAM_IO_ERROR if an I/O error occured. see JAM_Errno() JAM_BAD_PARAM if BaseMsg_I is 0 or NewBase_PPS is NULL Example { int Result_I; Result_I = JAM_CreateMB( "c:\\jam\\mybase", 1, &Base_PS ); if ( Result_I ) printf("JAM_CreateMB returned %d.\n", Result_I ); } ==================================== JAM_RemoveMB - Remove a message base ==================================== Syntax int JAM_RemoveMB( ErrorBase_PS, uchar* Basename_PC ); Description Deletes all files associated with a message base. No checking is done as to whether the message base is currently open or not. Parameters ErrorBase_PS The message base in which to store the I/O error, if any. This parameter does *NOT* specify the message to be removed, it is only used for error tracking purposes. If an i/o error occurs when removing the message base files, this message base handler will simply hold the error code. Basename_PC The path and base filename of the message base to remove. Returns 0 if successful JAM_IO_ERROR if an I/O error occured. see JAM_Errno() JAM_BAD_PARAM if ErrorBase_PS is NULL Example { int Result_I; Result_I = JAM_RemoveMB( Base_PS, "c:\\jam\\mybase" ); if ( Result_I ) { printf("JAM_RemoveMB returned %d.\n", Result_I ); if ( Result_I == JAM_IO_ERROR ) printf( "i/o error %d\n", JAM_Errno( ErrorBase_PS ) ); } } =================================================== JAM_LockMB - Lock message base for exclusive access =================================================== Syntax int JAM_LockMB( t_JamBase* Base_PS ); Description Locks the currently open message base so that no other programs may modify it. The message base should be locked for only small periods of time, or the performance of tossers and other software may be affected. Parameters Base_PS The message base to lock Returns 0 if successful JAM_IO_ERROR if an I/O error occured. see JAM_Errno() JAM_LOCK_FAILED if the message base is currently locked by another process JAM_BAD_PARAM if Base_PS is NULL Example { int Result_I; while ( 1 ) { Result_I = JAM_LockMB( Base_PS ); if ( Result_I ) { if ( Result_I == JAM_LOCK_FAILED ) /* base locked by someone else, wait for unlock */ sleep( 1 ); else { /* error */ printf("JAM_LockMB returned %d.\n", Result_I ); return -1; } } } } ================================== JAM_UnlockMB - Unlock message base ================================== Syntax int JAM_UnlockMB( s_JamBase* Base_PS ); Description Unlocks message base, allowing other programs to modify it. Parameters Base_PS The message base to unlock Returns 0 if successful JAM_IO_ERROR if an I/O error occured. see JAM_Errno() JAM_BAD_PARAM if Base_PS is NULL Example { int Result_I; Result_I = JAM_UnlockMB( Base_PS ); if ( Result_I ) printf("JAM_UnlockMB returned %d.\n", Result_I ); } =========================================== JAM_ReadMBHeader - Read message base header =========================================== Syntax int JAM_ReadMBHeader( s_JamBase* Base_PS, s_JamBaseHeader* Header_PS ); Description Reads the message base header from the start of the JAM header file. Parameters Base_PS The message base to use Header_PS A pointer to a base header structure where the base header will be stored. Returns 0 if successful JAM_BAD_PARAM if Base_PS or Header_PS is NULL JAM_IO_ERROR if an I/O error occured. see JAM_Errno() Example { s_JamBaseHeader BaseHeader_S; int Result_I; Result_I = JAM_ReadMBHeader( Base_PS, &BaseHeader_S ); if ( Result_I ) printf("JAM_ReadMBHeader returned %d.\n", Result_I ); } ============================================= JAM_WriteMBHeader - Write message base header ============================================= Syntax int JAM_WriteMBHeader( s_JamBase* Base_PS, s_JamBaseHeader* Header_PS ); Description Increases the ModCounter field by one, resets the header signature and writes the message base header to the start of the JAM header file. Parameters Base_PS The message base to use Header_PS A pointer to the base header to be stored Returns 0 if successful JAM_BAD_PARAM if Base_PS or Header_PS is NULL JAM_IO_ERROR if an I/O error occured. see JAM_Errno() JAM_NOT_LOCKED if the message base is not locked Example { s_JamBaseHeader BaseHeader_S; int Result_I; /* modify header here */ Result_I = JAM_WriteMBHeader( &BaseHeader_S ); if ( Result_I ) printf("JAM_WriteMBHeader returned %d.\n", Result_I ); } ===================================== JAM_FindUser - Find message to a user ===================================== Syntax int JAM_FindUser( s_JamBase* Base_PS, ulong UserCrc_I, ulong StartMsg_I, ulong* MsgNo_PI ); Description Scans the message base looking for a message written to a specific user. Parameters Base_PS The message base to use UserCrc_I The CRC32 value for the searched name StartMsg_I The first message number to look at. This value is not the message's unique number, but rather the absolute position of the message in the message base. Message 0 therefore means the first message. MsgNo_PI A pointer to a variable where the message number for the found message will be stored. This number is the absolute message position in the message base. Message 0 means the first message. Returns 0 if a message was found JAM_NO_USER if no message was found JAM_IO_ERROR if an I/O error occured. see JAM_Errno() Example { uchar Name_AC[32]; int Result_I; ulong Crc_I; ulong Msg_I; strcpy( Name_AC, "Bjorn Stenberg" ); Crc_I = JAM_Crc32( Name_AC, strlen( Name_AC ) ); Result_I = JAM_FindUser( Base_PS, Crc_I, 0, &Msg_I ); switch ( Result_I ) { case JAM_NO_USER: printf("No message for me.\n"); break; case JAM_IO_ERROR: printf("IO error %d\n", JAM_Errno() ); break; } } ========================================================== JAM_GetMBSize - Get the number of messages in message base ========================================================== Syntax int JAM_GetMBSize( s_JamBase* Base_PS, ulong* Messages_PI ); Description Finds out the number of messages (deleted and undeleted) in the message base. Parameters Base_PS The message base to use Messages_PI A pointer to a variable where the number of messages will be stored. Returns 0 if successful JAM_IO_ERROR if an I/O error occured. see JAM_Errno() Example { int Result_I; ulong Size_I; Result_I = JAM_GetMBSize( Base_PS, &Size_I ); if ( Result_I ) printf("JAM_GetMBSize returned %d.\n", Result_I ); } -------------------------------------------------------------------------- Message functions ----------------- These functions handle individual JAM messages. A JAM message contains of three parts: * Message Header * Message Header Subfields * Message Text The message header is a simple C structure and the message text is a simple text buffer. The subfields, however, are a bit more tricky. These contain everything that is not covered by the header, including the TO, FROM, SUBJECT fields, origin and destination network adresses etc. There can be an unlimited number of subfields to a message. In this routine library the subfields are encapsulated by a 'subfield packet', which is handled by its own set of routines. See a later section of this document for an explanation of those. ============================================================= JAM_ReadMsgHeader - Read a message's header and its subfields ============================================================= Syntax int JAM_ReadMsgHeader( s_JamBase* Base_PS, ulong MsgNo_I, s_JamMsgHeader* Header_PS, s_JamSubPacket** Subfields_PPS ); Description Reads a message header and (optionally) the message header subfields. Parameters Base_PS The message base to use MsgNo_I The message number, i.e. the absolute position of the message in the message base. Message 0 is the first message. Header_PS A pointer to a message header structure where the message header will be stored. Subfields_PPS A pointer to a subpacket pointer, where the subfield packet handle will be stored. If this parameter is NULL, no subfields are read. Returns 0 if successful JAM_IO_ERROR if an I/O error occured. see JAM_Errno() JAM_NO_MEMORY if a memory allocation failed JAM_NO_MESSAGE if message has been removed JAM_CORRUPT_MSG if message subfields are corrupted Example { s_JamMsgHeader Header_S; s_JamSubPacket* SubPack_PS int Result_I; Result_I = JAM_ReadMsgHeader( 0, &Header_S, &SubPack_PS ); if ( Result_I ) printf("JAM_ReadMsgHeader returned %d.\n", Result_I ); } ======================================= JAM_ReadMsgText - Read a message's text ======================================= Syntax int JAM_ReadMsgText( s_JamBase* Base_PS, ulong Offset_I, ulong Length_I, uchar* Buffer_PC ); Description Reads the body text associated with a message. Parameters Base_PS The message base to use Offset_I The text position in the text file. This information is stored in the message header. Length_I The text length. This information is stored in the message header. Buffer_PC A pointer to where the text should be stored. Returns 0 if successful JAM_IO_ERROR if an I/O error occured. see JAM_Errno() Example { s_JamMsgHeader Header_S; uchar* Buffer_PC; int Result_I; /* read msg header */ Result_I = JAM_ReadMsgHeader( Base_PS, 0, &Header_S, &SubPack_PS ); if ( Result_I ) { printf("JAM_ReadMsgHeader returned %d.\n", Result_I ); return; } /* allocate buffer text */ Buffer_PC = (uchar*) malloc( Header_S.TxtLen ); if ( !Buffer_PC ) { printf("malloc failed.\n"); return; } /* read text */ Result_I = JAM_ReadMsgText( Base_PS, Header_S.TxtOffset, Header_S.TxtLen, Buffer_PC ); if ( Result_I ) printf("JAM_ReadMsgText returned %d.\n", Result_I ); free( Buffer_PC ); } ============================================== JAM_AddMessage - Add a message to message base ============================================== Syntax int JAM_AddMessage( s_JamBase* Base_PS, s_JamMsgHeader* Header_PS, s_JamSubPacket* SubPack_PS, uchar* Text_PC, ulong TextLen_I ); Description Adds a message to the message base. Fully automatic. Parameters Base_PS The message base to use Header_PS A pointer to the message header struct. The function will set the following header fields: Signature, Revision, TxtOffset, TxtLen, SubfieldLen and MsgNum. Whatever you set these fields to will be overwritten. SubPack_PS A subfield packet handler, containing all subfields for the message. Text_PC A pointer to the first byte of the message text. TextLen_I The length of the message text, excluding any zero termination characters. Returns 0 if successful JAM_IO_ERROR if an I/O error occured. see JAM_Errno() JAM_NOT_LOCKED if the message base is not locked Example { s_JamSubPacket* SubPacket_PS; s_JamSubfield Subfield_S; s_JamMsgHeader Header_S; uchar Text_AC[64]; uchar Field_AC[64]; /* ** Fix message header */ JAM_ClearMsgHeader( &Header_S ); Header_S.DateWritten = time(NULL); /* ** Create subfield packet */ SubPacket_PS = JAM_NewSubPacket(); if ( !SubPacket_PS ) { printf("JAM_NewSubPacket returned NULL.\n" ); return; } /* set up subfield 1 */ strcpy( Field_AC, "This is field #1" ); Subfield_S.LoID = JAMSFLD_SENDERNAME; Subfield_S.HiID = 0; Subfield_S.DatLen = strlen( Field_AC ); Subfield_S.Buffer = Field_AC; JAM_PutSubfield( SubPacket_PS, &Subfield_S ); /* set up subfield 2 */ strcpy( Field_AC, "This is field #2" ); Subfield_S.LoID = JAMSFLD_RECVRNAME; Subfield_S.HiID = 0; Subfield_S.DatLen = strlen( Field_AC ); Subfield_S.Buffer = Field_AC; JAM_PutSubfield( SubPacket_PS, &Subfield_S ); /* ** Add message */ strcpy( Text_AC, "Hello world!\nThis is a test."); /* [lock the message base] */ Result_I = JAM_AddMessage( Base_PS, &Header_S, SubPacket_PS, Text_AC, strlen( Text_AC ) ); if ( Result_I ) { printf("JAM_AddMessage returned %d.\n", Result_I ); return; } /* [unlock the message base] */ JAM_DelSubPacket( SubPacket_PS ); } ================================================================= JAM_AddEmptyMessage - Add a empty message entry to a message base ================================================================= Syntax int JAM_AddEmptyMessage( s_JamBase* Base_PS); Description Adds an empty message header to the message base. Useful when writing a messagebase maintenance utility. Parameters Base_PS The message base to use Returns 0 if successful JAM_IO_ERROR if an I/O error occured. see JAM_Errno() JAM_NOT_LOCKED if the message base is not locked Example none =============================================== JAM_ChangeMsgHeader - Change a message's header =============================================== Syntax int JAM_ChangeMsgHeader( s_JamBase* Base_PS, ulong MsgNo_I, s_JamMsgHeader* Header_PS ); Description Writes over an old message header with a new one. Only the header - not the subfields - can be changed due to the subfields' dynamic size. NOTE! Use this function with caution. It is easy to corrupt a message by giving it an incorrect header. Parameters Base_PS The message base to use MsgNo_I The absolute message number. Message #0 is the first in the message base. Header_PS A pointer to the header structure to write. Returns 0 if successful JAM_IO_ERROR if an I/O error occured. see JAM_Errno() JAM_NOT_LOCKED if the message base is not locked Example { s_JamMsgHeader Header_S; int Result_I; /* [lock the message base] */ Result_I = JAM_ReadMsgHeader( Base_PS, 0, &Header_S, NULL ); if ( Result_I ) printf("JAM_ReadMsgHeader returned %d.\n", Result_I ); Header_S.TimesRead++; Result_I = JAM_ChangeMsgHeader( Base_PS, 0, &Header_S ); if ( Result_I ) printf("JAM_ChangeMsgHeader returned %d.\n", Result_I ); /* [unlock the message base] */ } ===================================================== JAM_ClearMsgHeader - Clear a message header structure ===================================================== Syntax int JAM_ClearMsgHeader( s_JamMsgHeader* Header_PS ); Description Clears a message header structure and prepares it for use. This includes setting the Signature field and the Revision field to their correct values, and setting the CRC fields to JAM_NO_CRC. Parameters Header_PS A pointer to the structure to prepare. Returns 0 if successful JAM_BAD_PARAM if Header_PS is NULL =================================================== JAM_DeleteMessage - Delete message from messagebase =================================================== Syntax int JAM_DeleteMessage( s_JamBase* Base_PS, ulong MsgNo_I ); Description Deletes message from messagebase by setting HdrOffset and UserCRC in index to 0xFFFFFFFF. ActiveMsgs in base header also updated. Parameters Base_PS The message base to use MsgNo_I The absolute message number. Message #0 is the first in the message base. Returns 0 if successful JAM_IO_ERROR if an I/O error occured. see JAM_Errno() JAM_NOT_LOCKED if the message base is not locked Example none -------------------------------------------------------------------------- Subfield packet functions ------------------------- As described earlier, a subfield is a part of the message header. Due to the complexity of the different network types in use, it is not feasible to try and cram all data into one header struct. Therefore, JAM uses a fairly small header struct and instead marks all additional data fields as 'subfields'. In order to make life a little more easy, I have used the concept of a container for all subfields. I call it a 'Subfield Packet'. It is identified by a struct pointer, and should be looked upon as a file or a list that you manipulate via the following four functions: =============================================== JAM_NewSubPacket - Create a new subfield packet =============================================== Syntax s_JamSubPacket* JAM_NewSubPacket( void ); Description Creates a new, empty, subfield packet. Parameters None Returns The subpacket handle, if successful, or NULL if a memory allocation failed. Example { s_JamSubPacket* SubPacket_PS; SubPacket_PS = JAM_NewSubPacket(); if ( !SubPacket_PS ) { printf("JAM_NewSubPacket returned NULL.\n" ); return; } } =========================================== JAM_DelSubPacket - Delete a subfield packet =========================================== Syntax int JAM_DelSubPacket( s_JamSubPacket* SubPack_PS ); Description Frees all memory used by a subfield packet. All subfields in the packet will be lost and the packet handle will not be valid any more. Parameters SubPack_PS The subfield packet to delete Returns 0 if successful JAM_BAD_PARAM if SubPack_PS is NULL. Example { s_JamSubPacket* SubPacket_PS; SubPacket_PS = JAM_NewSubPacket(); if ( !SubPacket_PS ) { printf("JAM_NewSubPacket returned NULL.\n" ); return; } SubPacket_PS = JAM_DelSubPacket(); if ( !SubPacket_PS ) { printf("JAM_DelSubPacket returned NULL.\n" ); return; } } ======================================================================= JAM_GetSubfield - Get a subfield from a subfield packet (not reentrant) ======================================================================= Syntax s_JamSubfield* JAM_GetSubfield( s_JamSubPacket* SubPack_PS ); Description Returns a pointer to the first/next subfield struct in the subfield packet. WARNING: This function is not reentrant and should not be used in multi-threaded applications unless you know what you are doing. Use JAM_GetSubfield_R instead when a reentrant function is needed. Parameter SubPack_PS The subfield packet to use. If this parameter is NULL, the next subfield from the subfield packet previously scanned will be returned. Returns A pointer to a subfield, if successful, or NULL if there are no more subfields in the packet. Example { s_JamSubPacket* SubPack_PS; s_JamSubfield* Subfield_PS; s_JamMsgHeader Header_S; int Result_I; Result_I = JAM_ReadMsgHeader( 0, &Header_S, &SubPack_PS ); if ( Result_I ) printf("JAM_ReadMsgHeader returned %d.\n", Result_I ); for ( Subfield_PS = JAM_GetSubfield( SubPack_PS ); Subfield_PS; Subfield_PS = JAM_GetSubfield( NULL ) ) printf("Subfield id %d\n", Subfield_PS->LoID ); JAM_DelSubPacket( SubPack_PS ); } ===================================================================== JAM_GetSubfield_R - Get a subfield from a subfield packet (reentrant) ===================================================================== Syntax s_JamSubfield* JAM_GetSubfield( s_JamSubPacket* SubPack_PS, ulong* Count_PI ); Description Returns a pointer to the first/next subfield struct in the subfield packet. This function is a reentrant replacement for JAM_GetSubfield. Parameter SubPack_PS The subfield packet to use. Count_PI Pointer to a variable that contains the number of the subfield to retrieve. The variable should be set to zero the first time the function is called and is then automatically increased by the function for any subsequent calls. Returns A pointer to a subfield, if successful, or NULL if there are no more subfields in the packet. Example { s_JamSubPacket* SubPack_PS; s_JamSubfield* Subfield_PS; s_JamMsgHeader Header_S; ulong Count_I; int Result_I; Result_I = JAM_ReadMsgHeader( 0, &Header_S, &SubPack_PS ); if ( Result_I ) printf("JAM_ReadMsgHeader returned %d.\n", Result_I ); Count_I = 0; while( ( Subfield_PS = JAM_GetSubfield_R( SubPack_PS , &Count_I ) ) ) printf("Subfield id %d\n", Subfield_PS->LoID ); JAM_DelSubPacket( SubPack_PS ); } ======================================================= JAM_PutSubfield - Put a subfield into a subfield packet ======================================================= Syntax int JAM_PutSubfield( s_JamSubPacket* SubPack_PS, s_JamSubfield* Subfield_PS ); Description Puts a subfield into a subfield packet. The subfield is copied before being put into the subfield packet. Parameters SubPack_PS The subfield packet to add to Subfield_PS The subfield to put in the packet Returns 0 if successful JAM_NO_MEMORY if a memory allocation failed Example { s_JamSubPacket* SubPacket_PS; s_JamSubfield Subfield_S; uchar Field_AC[64]; SubPacket_PS = JAM_NewSubPacket(); if ( !SubPacket_PS ) { printf("JAM_NewSubPacket returned NULL.\n" ); return; } /* set up subfield 1 */ strcpy( Field_AC, "This is field #1" ); Subfield_S.LoID = JAMSFLD_SENDERNAME; Subfield_S.HiID = 0; Subfield_S.DatLen = strlen( Field_AC ); Subfield_S.Buffer = Field_AC; JAM_PutSubfield( SubPacket_PS, &Subfield_S ); /* set up subfield 2 */ strcpy( Field_AC, "This is field #2" ); Subfield_S.LoID = JAMSFLD_RECVRNAME; Subfield_S.HiID = 0; Subfield_S.DatLen = strlen( Field_AC ); Subfield_S.Buffer = Field_AC; JAM_PutSubfield( SubPacket_PS, &Subfield_S ); JAM_DelSubPacket( SubPacket_PS ); } -------------------------------------------------------------------------- LastRead functions ------------------ JAM implements the often-used concept of high water marking for remembering which user read how many messages in each area. Personally I think this concept stinks, since it does not store *which* messages a user has read, only the number of the highest message he has read. But since it's a part of JAM and it's fairly straightforward and easy, I've implemented two support functions for it. I would, however, strongly recommend all BBS programmers to use proper message mapping systems instead, so your users can read their messages in whatever order they wish. ========================================= JAM_ReadLastRead - Read a lastread record ========================================= Syntax int JAM_ReadLastRead( s_JamBase* Base_PS, ulong User_I, s_JamLastRead* Record_PS ); Description Reads a lastread record from the lastread file. Parameter Base_PS The message base to use User_I A system-unique user number. Record_PS A pointer to the lastread struct where the record will be stored. Returns 0 if successful JAM_BAD_PARAM if Record_PS is NULL JAM_IO_ERROR if an I/O error occured. see JAM_Errno() JAM_NO_USER if the user number was not found Example { int Result_I; s_JamLastRead LastRead_S; Result_I = JAM_ReadLastRead( Base_PS, 4711, &LastRead_S ); if ( Result_I ) printf("JAM_ReadLastRead returned %d\n", Result_I ); } =========================================== JAM_WriteLastRead - Write a lastread record =========================================== Syntax int JAM_WriteLastRead( s_JamBase* Base_PS, ulong User_I, s_JamLastRead* Record_PS ); Description Writes a lastread record to the lastread file. If the user number could not be found, the record will be appended to the end of the file. Parameter Base_PS The message base to use User_I A system-unique user number Record_PS A pointer to the lastread struct to be written Returns 0 if successful JAM_BAD_PARAM if Record_PS is NULL JAM_IO_ERROR if an I/O error occured. see JAM_Errno() Example { int Result_I; s_JamLastRead LastRead_S; Result_I = JAM_WriteLastRead( Base_PS, 4711, &LastRead_S ); if ( Result_I ) printf("JAM_WriteLastRead returned %d\n", Result_I ); } -------------------------------------------------------------------------- Miscellanous functions ---------------------- ============================================== JAM_Crc32 - Calculate CRC32 on a block of data ============================================== Syntax ulong JAM_Crc32( uchar* Buffer_PC, ulong Length_I ); Description Calculates the Crc32 value for a block of data. All ASCII characters are converted to lowercase before calculating the CRC (the input data is unchanged). Parameters Buffer_PC A pointer to the first byte of the data block Length_I The number of bytes in the data block Returns The Crc32 value Example { ulong Crc_I; uchar Text_AC[32]; strcpy( Text_AC, "Hello world!\n"); Crc_I = JAM_Crc32( Text_AC, strlen( Text_AC ) ); } ============================= JAM_Errno - Specify I/O error ============================= Syntax int JAM_Errno( s_JamBase* Base_PS ); Description When any of these library routines return JAM_IO_ERROR, you can call this function to find out exactly what went wrong. Parameters Base_PS The message base to use Returns Standard 'errno' values, as the C compiler generated them, or if the I/O error was system specific, the return code is (10000 + system status code). Examples { int Result_I; uchar Text_AC[10]; /* generate an I/O error */ Result_I = JAM_ReadMsgText( 0xffffffff, 10, Text_AC ); if ( Result_I ) { errno = JAM_Errno( Base_PS ); perror("JAM i/o error"); } } crashmail-0.71/src/jamlib/Makefile.os20100644000000000000000000000106510073762726016306 0ustar rootrootCC = gcc -Wall -D__OS2__ -DINCL_DOSPROCESS AR = ar -ru RM = del OBJS = crc32.o mbase.o message.o lastread.o subpack.o structrw.o jamlib.a: $(OBJS) $(AR) jamlib.a $(OBJS) crc32.o: crc32.c jam.h $(CC) -c crc32.c -o crc32.o mbase.o: mbase.c jam.h $(CC) -c mbase.c -o mbase.o message.o: message.c jam.h $(CC) -c message.c -o message.o lastread.o: lastread.c jam.h $(CC) -c lastread.c -o lastread.o subpack.o: subpack.c jam.h $(CC) -c subpack.c -o subpack.o structrw.o: structrw.c jam.h $(CC) -c structrw.c -o structrw.o clean: $(RM) *.o *.a crashmail-0.71/src/jamlib/message.c0100644000000000000000000004012110073762726015730 0ustar rootroot/* JAMLIB - A JAM subroutine library Copyright (C) 1999 Björn Stenberg This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Changes made by Johan Billing 2000-04-16: - Changed source to use feof() instead of errno == EPASTEOF - Changed source to use structrw to read and write structures - Added JAM_AddEmptyMessage() - Added error messages JAM_NO_MESSAGE and JAM_CORRUPT_MSG for JAM_ReadMsgHeader() - #includes stdlib.h instead of malloc.h and memory.h - Fixed a bug that caused JAM_AddMessage() to fail when trying to add an empty message to the messagebase under Linux. Backported changes from JAMLIB 1.4.7 made by Johan Billing 2003-10-26 - Fixed memory leaks that would occur if JAM_ReadMsgHeader() failed - Added JAM_DeleteMessage() Other changes made by Johan Billing 2003-10-26 - Fixed comparison between signed and unsigned variable in JAM_AddMessage() - Improved handling of ActiveMsgs counter. JAM_AddMessage() now only increases ActiveMsgs if the added message does not have MSG_DELETED set. JAM_ChangeMsgHeader() decreases ActiveMsgs if MSG_DELETED is set and the message wasn't already deleted. JAM_DeleteMessage() now only decreases ActiveMsgs if the message wasn't already deleted. */ /*********************************************************************** ** ** Message.C -- Message handling ** ** Author: Bj”rn Stenberg (bjorn.stenberg@sth.frontec.se) ** ***********************************************************************/ #include #include #include #include #include "jam.h" #include "structrw.h" /*********************************************************************** ** ** JAM_ReadMsgHeader - Read message header ** ***********************************************************************/ int JAM_ReadMsgHeader( s_JamBase* Base_PS, ulong MsgNo_I, s_JamMsgHeader* Header_PS, s_JamSubPacket** SubfieldPack_PPS ) { s_JamIndex Index_S; if ( !Base_PS || !Header_PS ) return JAM_BAD_PARAM; /* find index record */ if ( fseek( Base_PS->IdxFile_PS, MsgNo_I * sizeof( s_JamIndex ), SEEK_SET ) ) { Base_PS->Errno_I = errno; return JAM_IO_ERROR; } /* read index record */ if ( 1 > freadjamindex(Base_PS->IdxFile_PS,&Index_S) ) { Base_PS->Errno_I = errno; return JAM_IO_ERROR; } /* message is not there */ if(Index_S.HdrOffset == 0xffffffff && Index_S.UserCRC == 0xffffffff) { return JAM_NO_MESSAGE; } /* find header */ if ( fseek( Base_PS->HdrFile_PS, Index_S.HdrOffset, SEEK_SET ) ) { Base_PS->Errno_I = errno; return JAM_IO_ERROR; } /* read header */ if ( 1 > freadjammsgheader(Base_PS->HdrFile_PS,Header_PS) ) { Base_PS->Errno_I = errno; return JAM_IO_ERROR; } /* are Subfields requested? */ if ( SubfieldPack_PPS && Header_PS->SubfieldLen ) { s_JamSubPacket* SubPacket_PS; s_JamSubfield Subfield_S; char* Buf_PC; char* Ptr_PC; char* Roof_PC; int BufSize_I = Header_PS->SubfieldLen; Buf_PC = (void*) malloc( BufSize_I ); if ( !Buf_PC ) return JAM_NO_MEMORY; /* read all subfields */ if ( 1 > fread( Buf_PC, BufSize_I, 1, Base_PS->HdrFile_PS ) ) { Base_PS->Errno_I = errno; free (Buf_PC); return JAM_IO_ERROR; } SubPacket_PS = JAM_NewSubPacket(); if ( !SubPacket_PS ) { free (Buf_PC); return JAM_NO_MEMORY; } Roof_PC = Buf_PC + BufSize_I; /* cut out the subfields */ for ( Ptr_PC = Buf_PC; Ptr_PC < Roof_PC; Ptr_PC += Subfield_S.DatLen + SIZE_JAMSAVESUBFIELD ) { int Status_I; getjamsubfield(Ptr_PC,&Subfield_S); if((char *)Subfield_S.Buffer + Subfield_S.DatLen > Roof_PC) { JAM_DelSubPacket( SubPacket_PS ); free (Buf_PC); return JAM_CORRUPT_MSG; } Status_I = JAM_PutSubfield( SubPacket_PS, &Subfield_S ); if ( Status_I ) { JAM_DelSubPacket( SubPacket_PS ); free (Buf_PC); return Status_I; } } free( Buf_PC ); *SubfieldPack_PPS = SubPacket_PS; } else if ( SubfieldPack_PPS ) /* fields requested but none found */ /* return an empty packet */ *SubfieldPack_PPS = JAM_NewSubPacket(); return 0; } /*********************************************************************** ** ** JAM_ReadMsgText - Read message text ** ***********************************************************************/ int JAM_ReadMsgText( s_JamBase* Base_PS, ulong Offset_I, ulong Length_I, uchar* Buffer_PC ) { if ( !Base_PS || !Buffer_PC ) return JAM_BAD_PARAM; if ( !Length_I ) return 0; if ( fseek( Base_PS->TxtFile_PS, Offset_I, SEEK_SET ) ) { Base_PS->Errno_I = errno; return JAM_IO_ERROR; } if ( 1 > fread( Buffer_PC, Length_I, 1, Base_PS->TxtFile_PS ) ) { Base_PS->Errno_I = errno; return JAM_IO_ERROR; } return 0; } /*********************************************************************** ** ** JAM_ChangeMsgHeader - Change a message header ** ***********************************************************************/ int JAM_ChangeMsgHeader( s_JamBase* Base_PS, ulong MsgNo_I, s_JamMsgHeader* Header_PS ) { s_JamBaseHeader BaseHeader_S; s_JamMsgHeader OldHeader_S; s_JamIndex Index_S; int Status_I; if ( !Base_PS ) return JAM_BAD_PARAM; if ( !Base_PS->Locked_I ) return JAM_NOT_LOCKED; /* read message base header */ Status_I = JAM_ReadMBHeader( Base_PS, &BaseHeader_S ); if ( Status_I ) return Status_I; /* find index record */ if ( fseek( Base_PS->IdxFile_PS, MsgNo_I * sizeof( s_JamIndex ), SEEK_SET ) ) { Base_PS->Errno_I = errno; return JAM_IO_ERROR; } /* read index record */ if ( 1 > freadjamindex(Base_PS->IdxFile_PS,&Index_S) ) { Base_PS->Errno_I = errno; return JAM_IO_ERROR; } /* find header */ if ( fseek( Base_PS->HdrFile_PS, Index_S.HdrOffset, SEEK_SET ) ) { Base_PS->Errno_I = errno; return JAM_IO_ERROR; } /* read old message header */ if ( 1 > freadjammsgheader( Base_PS->HdrFile_PS, &OldHeader_S ) ) { Base_PS->Errno_I = errno; return JAM_IO_ERROR; } /* find header */ if ( fseek( Base_PS->HdrFile_PS, Index_S.HdrOffset, SEEK_SET ) ) { Base_PS->Errno_I = errno; return JAM_IO_ERROR; } /* write header */ if ( 1 > fwritejammsgheader(Base_PS->HdrFile_PS,Header_PS) ) { Base_PS->Errno_I = errno; return JAM_IO_ERROR; } if( ( Header_PS->Attribute & MSG_DELETED ) && !(OldHeader_S.Attribute & MSG_DELETED) ) { /* message is deleted now but wasn't before */ BaseHeader_S.ActiveMsgs--; } Status_I = JAM_WriteMBHeader( Base_PS, &BaseHeader_S ); if ( Status_I ) return Status_I; return 0; } /*********************************************************************** ** ** JAM_AddMessage - Add a message to a message base ** ***********************************************************************/ int JAM_AddMessage( s_JamBase* Base_PS, s_JamMsgHeader* Header_PS, s_JamSubPacket* SubPack_PS, uchar* Text_PC, ulong TextLen_I ) { s_JamBaseHeader BaseHeader_S; s_JamIndex Index_S; long Offset_I; int Status_I; ulong TotLen_I; if ( !Base_PS ) return JAM_BAD_PARAM; if ( !Base_PS->Locked_I ) return JAM_NOT_LOCKED; /* read message base header */ Status_I = JAM_ReadMBHeader( Base_PS, &BaseHeader_S ); if ( Status_I ) return Status_I; /* ** Add text if any */ Header_PS->TxtOffset = 0; Header_PS->TxtLen = 0; if(Text_PC && TextLen_I!=0) { /* go to end of text file */ if ( fseek( Base_PS->TxtFile_PS, 0, SEEK_END ) ) { Base_PS->Errno_I = errno; return JAM_IO_ERROR; } /* store text offset (for header) */ Offset_I = ftell( Base_PS->TxtFile_PS ); if ( Offset_I == -1 ) { Base_PS->Errno_I = errno; return JAM_IO_ERROR; } Header_PS->TxtOffset = Offset_I; Header_PS->TxtLen = TextLen_I; /* write text */ if ( 1 > fwrite( Text_PC, TextLen_I, 1, Base_PS->TxtFile_PS ) ) { Base_PS->Errno_I = errno; return JAM_IO_ERROR; } } /* ** Add header */ /* go to end of header file */ if ( fseek( Base_PS->HdrFile_PS, 0, SEEK_END ) ) { Base_PS->Errno_I = errno; return JAM_IO_ERROR; } /* calculate the size of all Subfields */ TotLen_I = 0; if ( SubPack_PS ) { s_JamSubfield* Subfield_PS; for ( Subfield_PS = JAM_GetSubfield( SubPack_PS ); Subfield_PS; Subfield_PS = JAM_GetSubfield( NULL ) ) TotLen_I += sizeof( s_JamSaveSubfield ) + Subfield_PS->DatLen; } Header_PS->SubfieldLen = TotLen_I; /* go to end of index file */ if ( fseek( Base_PS->IdxFile_PS, 0, SEEK_END ) ) { Base_PS->Errno_I = errno; return JAM_IO_ERROR; } /* find out new message number (for message header) */ Offset_I = ftell( Base_PS->IdxFile_PS ); if ( Offset_I == -1 ) { Base_PS->Errno_I = errno; return JAM_IO_ERROR; } /* update header */ Header_PS->MsgNum = Offset_I / sizeof( s_JamIndex ) + BaseHeader_S.BaseMsgNum; memcpy( Header_PS->Signature, HEADERSIGNATURE, 4 ); Header_PS->Revision = CURRENTREVLEV; /* go to end of header file */ if ( fseek( Base_PS->HdrFile_PS, 0, SEEK_END ) ) { Base_PS->Errno_I = errno; return JAM_IO_ERROR; } /* find out new header offset (for index record) */ Offset_I = ftell( Base_PS->HdrFile_PS ); if ( Offset_I == -1 ) { Base_PS->Errno_I = errno; return JAM_IO_ERROR; } Index_S.HdrOffset = Offset_I; /* write new header */ if ( 1 > fwritejammsgheader(Base_PS->HdrFile_PS,Header_PS) ) { Base_PS->Errno_I = errno; return JAM_IO_ERROR; } /* write Subfields */ if ( SubPack_PS ) { s_JamSubfield* Subfield_PS; uchar User_AC[101]; /* clear username */ User_AC[0] = 0; for ( Subfield_PS = JAM_GetSubfield( SubPack_PS ); Subfield_PS; Subfield_PS = JAM_GetSubfield( NULL ) ) { /* first, save Subfield header */ if ( 1 > fwritejamsavesubfield(Base_PS->HdrFile_PS,(s_JamSaveSubfield *)Subfield_PS) ) { Base_PS->Errno_I = errno; return JAM_IO_ERROR; } /* then, save Subfield data if any*/ if(Subfield_PS->DatLen) { if ( 1 > fwrite( Subfield_PS->Buffer, Subfield_PS->DatLen, 1, Base_PS->HdrFile_PS ) ) { Base_PS->Errno_I = errno; return JAM_IO_ERROR; } } /* store username for index file */ if ( Subfield_PS->LoID == JAMSFLD_RECVRNAME ) { memcpy( User_AC, Subfield_PS->Buffer, Subfield_PS->DatLen ); User_AC[ Subfield_PS->DatLen ] = 0; } } /* update index record */ if ( User_AC[0] ) Index_S.UserCRC = JAM_Crc32( User_AC, strlen( User_AC ) ); else Index_S.UserCRC = JAM_NO_CRC; } else /* update index record */ Index_S.UserCRC = JAM_NO_CRC; /* ** Add index */ /* write index record */ if ( 1 > fwritejamindex(Base_PS->IdxFile_PS,&Index_S) ) { Base_PS->Errno_I = errno; return JAM_IO_ERROR; } if(!(Header_PS->Attribute & MSG_DELETED)) BaseHeader_S.ActiveMsgs++; /* Only increase ActiveMsgs if MSG_DELETED not set */ /* write message base header */ Status_I = JAM_WriteMBHeader( Base_PS, &BaseHeader_S ); if ( Status_I ) return Status_I; return 0; } /*********************************************************************** ** ** JAM_AddEmptyMessage - Add a empty message entry to a message base ** ***********************************************************************/ int JAM_AddEmptyMessage( s_JamBase* Base_PS) { s_JamIndex Index_S; if ( !Base_PS ) return JAM_BAD_PARAM; if ( !Base_PS->Locked_I ) return JAM_NOT_LOCKED; /* go to end of index file */ if ( fseek( Base_PS->IdxFile_PS, 0, SEEK_END ) ) { Base_PS->Errno_I = errno; return JAM_IO_ERROR; } /* ** Add index */ Index_S.HdrOffset = 0xffffffff; Index_S.UserCRC = 0xffffffff; /* write index record */ if ( 1 > fwritejamindex(Base_PS->IdxFile_PS,&Index_S) ) { Base_PS->Errno_I = errno; return JAM_IO_ERROR; } return 0; } /*********************************************************************** ** ** JAM_DeleteMessage - Delete message from messagebase ** ***********************************************************************/ int JAM_DeleteMessage( s_JamBase* Base_PS, ulong MsgNo_I ) { s_JamBaseHeader BaseHeader_S; s_JamMsgHeader Header_S; s_JamIndex Index_S; int Status_I; ulong OldAttribute_I; if ( !Base_PS ) return JAM_BAD_PARAM; if ( !Base_PS->Locked_I ) return JAM_NOT_LOCKED; /* read message base header */ Status_I = JAM_ReadMBHeader( Base_PS, &BaseHeader_S ); if ( Status_I ) return Status_I; /* find index record */ if ( fseek( Base_PS->IdxFile_PS, MsgNo_I * sizeof( s_JamIndex ), SEEK_SET ) ) { Base_PS->Errno_I = errno; return JAM_IO_ERROR; } /* read index record */ if ( 1 > freadjamindex( Base_PS->IdxFile_PS, &Index_S ) ) { Base_PS->Errno_I = errno; return JAM_IO_ERROR; } /* message is not there */ if(Index_S.HdrOffset == 0xffffffff && Index_S.UserCRC == 0xffffffff) { return JAM_NO_MESSAGE; } /* find header */ if ( fseek( Base_PS->HdrFile_PS, Index_S.HdrOffset, SEEK_SET ) ) { Base_PS->Errno_I = errno; return JAM_IO_ERROR; } /* read header */ if ( 1 > freadjammsgheader( Base_PS->HdrFile_PS, &Header_S ) ) { Base_PS->Errno_I = errno; return JAM_IO_ERROR; } OldAttribute_I = Header_S.Attribute; Header_S.Attribute |= MSG_DELETED; /* find header */ if ( fseek( Base_PS->HdrFile_PS, Index_S.HdrOffset, SEEK_SET ) ) { Base_PS->Errno_I = errno; return JAM_IO_ERROR; } /* write header */ if ( 1 > fwritejammsgheader( Base_PS->HdrFile_PS, &Header_S ) ) { Base_PS->Errno_I = errno; return JAM_IO_ERROR; } /* find index record */ if ( fseek( Base_PS->IdxFile_PS, MsgNo_I * sizeof( s_JamIndex ), SEEK_SET ) ) { Base_PS->Errno_I = errno; return JAM_IO_ERROR; } Index_S.HdrOffset = 0xffffffff; Index_S.UserCRC = 0xffffffff; /* write index record */ if ( 1 > fwritejamindex(Base_PS->IdxFile_PS,&Index_S) ) { Base_PS->Errno_I = errno; return JAM_IO_ERROR; } if(!(OldAttribute_I & MSG_DELETED)) BaseHeader_S.ActiveMsgs--; /* decrease ActiveMsgs if the message wasn't already deleted */ /* write message base header */ Status_I = JAM_WriteMBHeader( Base_PS, &BaseHeader_S ); if ( Status_I ) return Status_I; return 0; } /*********************************************************************** ** ** JAM_Errno - Report the latest C library error code ** ***********************************************************************/ int JAM_Errno( s_JamBase* Base_PS ) { return Base_PS->Errno_I; } /*********************************************************************** ** ** JAM_ClearMsgHeader - Clear a message header ** ***********************************************************************/ int JAM_ClearMsgHeader( s_JamMsgHeader* Header_PS ) { if (!Header_PS) return JAM_BAD_PARAM; memset( Header_PS, 0, sizeof( s_JamMsgHeader ) ); memcpy( Header_PS->Signature, HEADERSIGNATURE, 4 ); Header_PS->Revision = CURRENTREVLEV; Header_PS->MsgIdCRC = JAM_NO_CRC; Header_PS->ReplyCRC = JAM_NO_CRC; Header_PS->PasswordCRC = JAM_NO_CRC; return 0; } crashmail-0.71/src/jamlib/Makefile.linux0100644000000000000000000000104710073762726016742 0ustar rootrootCC = gcc -D__LINUX__ -Wall AR = ar -ru RM = rm -f OBJS = crc32.o mbase.o message.o lastread.o subpack.o structrw.o jamlib.a : $(OBJS) $(AR) jamlib.a $(OBJS) crc32.o: crc32.c jam.h $(CC) -c crc32.c -o crc32.o mbase.o: mbase.c jam.h $(CC) -c mbase.c -o mbase.o message.o: message.c jam.h $(CC) -c message.c -o message.o lastread.o: lastread.c jam.h $(CC) -c lastread.c -o lastread.o subpack.o: subpack.c jam.h $(CC) -c subpack.c -o subpack.o structrw.o: structrw.c jam.h $(CC) -c structrw.c -o structrw.o clean: $(RM) *.o *.a crashmail-0.71/src/jamlib/Makefile.win320100644000000000000000000000106610073762726016546 0ustar rootrootCC = gcc -Wall AR = ar -ru RM = del OBJS = crc32.o mbase.o message.o lastread.o subpack.o structrw.o jamlib.a : $(OBJS) $(AR) jamlib.a $(OBJS) crc32.o: crc32.c jam.h $(CC) -c crc32.c -o crc32.o mbase.o: mbase.c jam.h $(CC) -c mbase.c -o mbase.o message.o: message.c jam.h $(CC) -c message.c -o message.o lastread.o: lastread.c jam.h $(CC) -c lastread.c -o lastread.o subpack.o: subpack.c jam.h $(CC) -c subpack.c -o subpack.o structrw.o: structrw.c jam.h $(CC) -c structrw.c -o structrw.o clean: $(RM) *.o *.a crashmail-0.71/src/jamlib/lastread.c0100644000000000000000000001075410073762726016114 0ustar rootroot/* JAMLIB - A JAM subroutine library Copyright (C) 1999 Björn Stenberg This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Changes made by Johan Billing 2000-04-16: - Changed source to use feof() instead of errno == EPASTEOF - Changed source to use structrw to read and write structures */ /*********************************************************************** ** ** LASTREAD.C -- Lastread pointer handling ** ** Author: Bj”rn Stenberg (bjorn.stenberg@sth.frontec.se) ** ***********************************************************************/ #include #include #include "jam.h" #include "structrw.h" /*********************************************************************** ** ** File global variables ** ***********************************************************************/ /*********************************************************************** ** ** JAM_ReadLastRead - Read LastRead record ** ***********************************************************************/ int JAM_ReadLastRead( s_JamBase* Base_PS, ulong User_I, s_JamLastRead* Record_PS ) { s_JamLastRead Record_S; int Pos_I; if (!Record_PS) return JAM_BAD_PARAM; if ( fseek( Base_PS->LrdFile_PS, 0, SEEK_SET ) ) { Base_PS->Errno_I = errno; return JAM_IO_ERROR; } for ( Pos_I = 0; ; Pos_I++ ) { if ( 1 > freadjamlastread(Base_PS->LrdFile_PS,&Record_S) ) { if ( feof(Base_PS->LrdFile_PS) ) return JAM_NO_USER; Base_PS->Errno_I = errno; return JAM_IO_ERROR; } if ( Record_S.UserID == User_I ) { Base_PS->LastUserPos_I = Pos_I; Base_PS->LastUserId_I = User_I; *Record_PS = Record_S; return 0; } } return 0; } /*********************************************************************** ** ** JAM_WriteLastRead - Write LastRead record ** ***********************************************************************/ int JAM_WriteLastRead( s_JamBase* Base_PS, ulong User_I, s_JamLastRead* Record_PS ) { s_JamLastRead Record_S; int Pos_I; if (!Record_PS) return JAM_BAD_PARAM; /* if the last read is stored */ if ( User_I == Base_PS->LastUserId_I ) { Pos_I = Base_PS->LastUserPos_I * sizeof( s_JamLastRead ); if ( fseek( Base_PS->LrdFile_PS, Pos_I, SEEK_SET ) ) { Base_PS->Errno_I = errno; return JAM_IO_ERROR; } /* be safe, check it */ if ( 1 > freadjamlastread(Base_PS->LrdFile_PS,&Record_S) ) { Base_PS->Errno_I = errno; return JAM_IO_ERROR; } /* is it where we expected it to be? */ if ( User_I == Record_S.UserID ) { if ( fseek( Base_PS->LrdFile_PS, Pos_I, SEEK_SET ) ) { Base_PS->Errno_I = errno; return JAM_IO_ERROR; } if ( 1 > fwritejamlastread(Base_PS->LrdFile_PS,Record_PS) ) { Base_PS->Errno_I = errno; return JAM_IO_ERROR; } fflush(Base_PS -> LrdFile_PS); return 0; } } /* no last position, or position incorrect */ if ( fseek( Base_PS->LrdFile_PS, 0, SEEK_SET ) ) { Base_PS->Errno_I = errno; return JAM_IO_ERROR; } for ( Pos_I = 0; ; Pos_I++ ) { if ( 1 > freadjamlastread(Base_PS->LrdFile_PS,&Record_S) ) { if ( feof(Base_PS->LrdFile_PS) ) { /* user not in file, append a new record */ if ( fseek( Base_PS->LrdFile_PS, 0, SEEK_END ) ) { Base_PS->Errno_I = errno; return JAM_IO_ERROR; } break; } Base_PS->Errno_I = errno; return JAM_IO_ERROR; } /* found the user? */ if ( Record_S.UserID == User_I ) { if ( fseek( Base_PS->LrdFile_PS, Pos_I * sizeof(s_JamLastRead), SEEK_SET ) ) { Base_PS->Errno_I = errno; return JAM_IO_ERROR; } break; } } if ( 1 > fwritejamlastread(Base_PS->LrdFile_PS,Record_PS) ) { Base_PS->Errno_I = errno; return JAM_IO_ERROR; } fflush( Base_PS->LrdFile_PS ); return 0; } crashmail-0.71/src/Makefile.os20100644000000000000000000001373107762407025015052 0ustar rootroot# Makefile for Linux # General PLATFORMDEF = -DPLATFORM_OS2 EXESUFFIX = .exe BINDIR = ../bin OBJDIR = obj INCDIR = ./ OSLIB = oslib_os2/oslib.a JAMLIB = 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) # Sum them up. Only include the messagebases you want to use MBDEFS = $(MBDEFS_MSG) $(MBDEFS_JAM) MBOBJS = $(MBOBJS_MSG) $(MBOBJS_JAM) DEFS = $(PLATFORMDEF) $(MBDEFS) $(NLDEFS) # Commands CC = gcc $(DEFS) -I $(INCDIR) -Wall RM = del STRIP = emxbind -s # 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)/crashmail.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)/crashmail$(EXESUFFIX) \ $(BINDIR)/crashstats$(EXESUFFIX) \ $(BINDIR)/crashlist$(EXESUFFIX) \ $(BINDIR)/crashgetnode$(EXESUFFIX) \ $(BINDIR)/crashmaint$(EXESUFFIX) \ $(BINDIR)/crashwrite$(EXESUFFIX) \ $(BINDIR)/crashexport$(EXESUFFIX) \ $(BINDIR)/crashlistout$(EXESUFFIX) $(BINDIR)/crashmail$(EXESUFFIX) : $(CMOBJS) $(SHOBJS) $(NLOBJS) $(MBOBJS) $(OSLIB) $(CC) -o $(BINDIR)/crashmail$(EXESUFFIX) $(CMOBJS) $(SHOBJS) $(NLOBJS) $(MBOBJS) $(OSLIB) $(STRIP) $(BINDIR)/crashmail$(EXESUFFIX) $(BINDIR)/crashstats$(EXESUFFIX) : tools/crashstats.c $(SHOBJS) $(OSLIB) $(CC) -o $(BINDIR)/crashstats$(EXESUFFIX) tools/crashstats.c $(SHOBJS) $(OSLIB) $(STRIP) $(BINDIR)/crashstats$(EXESUFFIX) $(BINDIR)/crashlist$(EXESUFFIX) : tools/crashlist.c $(SHOBJS) $(OSLIB) $(CC) -o $(BINDIR)/crashlist$(EXESUFFIX) tools/crashlist.c $(SHOBJS) $(OSLIB) $(STRIP) $(BINDIR)/crashlist$(EXESUFFIX) $(BINDIR)/crashgetnode$(EXESUFFIX) : tools/crashgetnode.c $(SHOBJS) $(CMNLLIB) $(OSLIB) $(CC) -o $(BINDIR)/crashgetnode$(EXESUFFIX) tools/crashgetnode.c $(SHOBJS) $(CMNLLIB) $(OSLIB) $(STRIP) $(BINDIR)/crashgetnode$(EXESUFFIX) $(BINDIR)/crashmaint$(EXESUFFIX) : tools/crashmaint.c $(SHOBJS) $(OSLIB) $(JAMLIB) $(CC) -o $(BINDIR)/crashmaint$(EXESUFFIX) tools/crashmaint.c $(SHOBJS) $(OSLIB) $(JAMLIB) $(STRIP) $(BINDIR)/crashmaint$(EXESUFFIX) $(BINDIR)/crashwrite$(EXESUFFIX) : tools/crashwrite.c $(SHOBJS) $(OSLIB) $(CC) -o $(BINDIR)/crashwrite$(EXESUFFIX) tools/crashwrite.c $(SHOBJS) $(OSLIB) $(STRIP) $(BINDIR)/crashwrite$(EXESUFFIX) $(BINDIR)/crashexport$(EXESUFFIX) : tools/crashexport.c $(SHOBJS) $(OSLIB) $(CC) -o $(BINDIR)/crashexport$(EXESUFFIX) tools/crashexport.c $(SHOBJS) $(OSLIB) $(STRIP) $(BINDIR)/crashexport$(EXESUFFIX) $(BINDIR)/crashlistout$(EXESUFFIX) : tools/crashlistout.c $(SHOBJS) $(OSLIB) $(CC) -o $(BINDIR)/crashlistout$(EXESUFFIX) tools/crashlistout.c $(SHOBJS) $(OSLIB) $(STRIP) $(BINDIR)/crashlistout$(EXESUFFIX) # crashmail $(OBJDIR)/crashmail.o : crashmail/crashmail.c $(CC) -c crashmail/crashmail.c -o $(OBJDIR)/crashmail.o $(OBJDIR)/logwrite.o : crashmail/logwrite.c $(CC) -c crashmail/logwrite.c -o $(OBJDIR)/logwrite.o $(OBJDIR)/dupe.o : crashmail/dupe.c $(CC) -c crashmail/dupe.c -o $(OBJDIR)/dupe.o $(OBJDIR)/stats.o : crashmail/stats.c $(CC) -c crashmail/stats.c -o $(OBJDIR)/stats.o $(OBJDIR)/misc.o : crashmail/misc.c $(CC) -c crashmail/misc.c -o $(OBJDIR)/misc.o $(OBJDIR)/safedel.o : crashmail/safedel.c $(CC) -c crashmail/safedel.c -o $(OBJDIR)/safedel.o $(OBJDIR)/toss.o : crashmail/toss.c $(CC) -c crashmail/toss.c -o $(OBJDIR)/toss.o $(OBJDIR)/scan.o : crashmail/scan.c $(CC) -c crashmail/scan.c -o $(OBJDIR)/scan.o $(OBJDIR)/pkt.o : crashmail/pkt.c $(CC) -c crashmail/pkt.c -o $(OBJDIR)/pkt.o $(OBJDIR)/memmessage.o : crashmail/memmessage.c $(CC) -c crashmail/memmessage.c -o $(OBJDIR)/memmessage.o $(OBJDIR)/handle.o : crashmail/handle.c $(CC) -c crashmail/handle.c -o $(OBJDIR)/handle.o $(OBJDIR)/node4dpat.o : crashmail/node4dpat.c $(CC) -c crashmail/node4dpat.c -o $(OBJDIR)/node4dpat.o $(OBJDIR)/config.o : crashmail/config.c $(CC) -c crashmail/config.c -o $(OBJDIR)/config.o $(OBJDIR)/outbound.o : crashmail/outbound.c $(CC) -c crashmail/outbound.c -o $(OBJDIR)/outbound.o $(OBJDIR)/areafix.o : crashmail/areafix.c $(CC) -c crashmail/areafix.c -o $(OBJDIR)/areafix.o $(OBJDIR)/filter.o : crashmail/filter.c $(CC) -c crashmail/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 : crashmail/mb.c $(CC) -c crashmail/mb.c -o $(OBJDIR)/mb.o $(OBJDIR)/mb_msg.o : crashmail/mb_msg.c $(CC) -c crashmail/mb_msg.c -o $(OBJDIR)/mb_msg.o $(OBJDIR)/mb_jam.o : crashmail/mb_jam.c $(CC) -c crashmail/mb_jam.c -o $(OBJDIR)/mb_jam.o # nl $(OBJDIR)/nl.o : crashmail/nl.c $(CC) -c crashmail/nl.c -o $(OBJDIR)/nl.o $(OBJDIR)/nl_cmnl.o : crashmail/nl_cmnl.c $(CC) -c crashmail/nl_cmnl.c -o $(OBJDIR)/nl_cmnl.o $(OBJDIR)/nl_v7p.o : crashmail/nl_v7p.c $(CC) -c crashmail/nl_v7p.c -o $(OBJDIR)/nl_v7p.o # Clean clean : $(RM) $(OBJDIR)/*.o crashmail-0.71/src/shared/0040755000000000000000000000000007762406457014164 5ustar rootrootcrashmail-0.71/src/shared/fidonet.h0100644000000000000000000000505307300264671015751 0ustar rootroot/* 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 crashmail-0.71/src/shared/jbstrcpy.c0100644000000000000000000000227007762367760016171 0ustar rootroot#include #include "shared/types.h" bool jbstrcpy(uchar *dest,uchar *src,ulong maxlen,ulong *jbc) { ulong d=0; ulong stopchar1,stopchar2; ulong 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 #include #include #include #include "shared/parseargs.h" bool parseargs(struct argument *arg,int argc, char **argv) { int i,j; for(i=1;i%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"); } crashmail-0.71/src/shared/parseargs.h0100644000000000000000000000074507300264671016313 0ustar rootroot#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 { ushort type; uchar *name; ushort flags; void *data; }; bool parseargs(struct argument *arg,int argc, char **argv); void printargs(struct argument *arg); #endif crashmail-0.71/src/shared/mystrncpy.c0100644000000000000000000000025707300264671016365 0ustar rootroot#include "shared/types.h" #include #include void mystrncpy(uchar *dest,uchar *src,ulong len) { strncpy(dest,src,(size_t)len-1); dest[len-1]=0; } crashmail-0.71/src/shared/mystrncpy.h0100644000000000000000000000021407300264671016363 0ustar rootroot#ifndef SHARED_MYSTRNCPY_H #define SHARED_MYSTRNCPY_H #include "shared/types.h" void mystrncpy(uchar *dest,uchar *src,ulong len); #endif crashmail-0.71/src/shared/expr.c0100644000000000000000000001551707763442613015307 0ustar rootroot#include #include #include "shared/types.h" #include "shared/expr.h" #include #include struct expr *expr_get(struct expr *expr,int *errpos,uchar **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,uchar **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(uchar *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)(uchar *str,int *errpos,uchar **errstr),int *errpos,uchar **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); } } crashmail-0.71/src/shared/expr.h0100644000000000000000000000037507762404171015304 0ustar rootrootstruct expr { uchar *buf; int parsepos; int offset; }; int expr_eval(struct expr *expr,int (*eval)(uchar *str,int *errpos,uchar **errstr),int *errpos,uchar **errstr); struct expr *expr_makeexpr(uchar *str); void expr_free(struct expr *expr); crashmail-0.71/src/shared/path.c0100644000000000000000000000133407300264671015246 0ustar rootroot#include #include #include #include #include void MakeFullPath(uchar *path,uchar *file,uchar *dest,ulong 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++]=(uchar)chr[0]; dest[d]=0; } } if(destsize-d-1 > 0) mystrncpy(&dest[d],file,destsize-d-1); } uchar *GetFilePart(uchar *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); } crashmail-0.71/src/shared/path.h0100644000000000000000000000015207300264671015250 0ustar rootroot void MakeFullPath(uchar *path,uchar *file,uchar *dest,ulong destsize); uchar *GetFilePart(uchar *str); crashmail-0.71/src/shared/types.h0100644000000000000000000000062607300264671015466 0ustar rootroot#ifndef SHARED_TYPES_H #define SHARED_TYPES_H #ifdef PLATFORM_LINUX #define NO_TYPEDEF_ULONG #define NO_TYPEDEF_USHORT #endif #ifndef NO_TYPEDEF_ULONG typedef unsigned long ulong; #endif #ifndef NO_TYPEDEF_USHORT typedef unsigned short ushort; #endif #ifndef NO_TYPEDEF_UCHAR typedef unsigned char uchar; #endif #ifndef NO_TYPEDEF_BOOL typedef int bool; #endif #define FALSE 0 #define TRUE 1 #endif crashmail-0.71/src/shared/jblist.c0100644000000000000000000000260507300264671015603 0ustar rootroot#include #include #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,ulong num) { struct jbNode *old=NULL,*tmp; ulong c; tmp=list->First; for(c=0;cNext; } 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); } } crashmail-0.71/src/shared/jblist.h0100644000000000000000000000063007300264671015604 0ustar rootroot#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,ulong num); void jbFreeNode(struct jbList *list,struct jbNode *node); #endif crashmail-0.71/src/shared/storedmsg.h0100644000000000000000000000056207300264671016330 0ustar rootrootstruct StoredMsg { uchar From[36]; uchar To[36]; uchar Subject[72]; uchar 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 */ }; crashmail-0.71/src/shared/node4d.c0100644000000000000000000000441107300265524015464 0ustar rootroot#include #include #include #include "node4d.h" bool Parse4DTemplate(uchar *buf, struct Node4D *node,struct Node4D *tpl) { ulong c,val; bool GotZone,GotNet,GotNode,GotVal; GotZone=FALSE; GotNet=FALSE; GotNode=FALSE; GotVal=FALSE; Copy4D(node,tpl); for(c=0;cZone=val; GotZone=TRUE; GotVal=FALSE; } else if(buf[c]=='/') { if(GotNet || GotNode) return(FALSE); if(GotVal) node->Net=val; GotNet=TRUE; GotVal=FALSE; } else if(buf[c]=='.') { if(GotNode) return(FALSE); if(GotVal) node->Node=val; GotNode=TRUE; GotVal=FALSE; } else if(buf[c]>='0' && buf[c]<='9') { if(!GotVal) { val=0; GotVal=TRUE; } val*=10; val+=buf[c]-'0'; } else return(FALSE); } if(GotVal) { if(GotZone && !GotNet) node->Net=val; else if(GotNode) node->Point=val; else node->Node=val; } return(TRUE); } bool Parse4D(uchar *buf, struct Node4D *node) { struct Node4D tpl4d = { 0,0,0,0 }; return Parse4DTemplate(buf,node,&tpl4d); } void Copy4D(struct Node4D *node1,struct Node4D *node2) { node1->Zone=node2->Zone; node1->Net=node2->Net; node1->Node=node2->Node; node1->Point=node2->Point; } int Compare4D(struct Node4D *node1,struct Node4D *node2) { if(node1->Zone!=0 && node2->Zone!=0) { if(node1->Zone > node2->Zone) return(1); if(node1->Zone < node2->Zone) return(-1); } if(node1->Net > node2->Net) return(1); if(node1->Net < node2->Net) return(-1); if(node1->Node > node2->Node) return(1); if(node1->Node < node2->Node) return(-1); if(node1->Point > node2->Point) return(1); if(node1->Point < node2->Point) return(-1); return(0); } void Print4D(struct Node4D *n4d,uchar *dest) { if(n4d->Point) sprintf(dest,"%u:%u/%u.%u",n4d->Zone, n4d->Net, n4d->Node, n4d->Point); else sprintf(dest,"%u:%u/%u",n4d->Zone, n4d->Net, n4d->Node); } crashmail-0.71/src/shared/node4d.h0100644000000000000000000000062207300264671015473 0ustar rootroot#ifndef NODE4D_H #define NODE4D_H #include struct Node4D { ushort Zone,Net,Node,Point; }; bool Parse4D(uchar *buf, struct Node4D *node); bool Parse4DTemplate(uchar *buf, struct Node4D *node,struct Node4D *tpl); void Copy4D(struct Node4D *node1,struct Node4D *node2); int Compare4D(struct Node4D *node1,struct Node4D *node2); void Print4D(struct Node4D *n4d,uchar *dest); #endif crashmail-0.71/src/Makefile.linux0100644000000000000000000001373007762407057015512 0ustar rootroot# Makefile for Linux # General PLATFORMDEF = -DPLATFORM_LINUX EXESUFFIX = BINDIR = ../bin OBJDIR = obj INCDIR = ./ OSLIB = oslib_linux/oslib.a JAMLIB = 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) # Sum them up. Only include the messagebases you want to use MBDEFS = $(MBDEFS_MSG) $(MBDEFS_JAM) MBOBJS = $(MBOBJS_MSG) $(MBOBJS_JAM) DEFS = $(PLATFORMDEF) $(MBDEFS) $(NLDEFS) # Commands CC = gcc $(DEFS) -I $(INCDIR) -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)/crashmail.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)/crashmail$(EXESUFFIX) \ $(BINDIR)/crashstats$(EXESUFFIX) \ $(BINDIR)/crashlist$(EXESUFFIX) \ $(BINDIR)/crashgetnode$(EXESUFFIX) \ $(BINDIR)/crashmaint$(EXESUFFIX) \ $(BINDIR)/crashwrite$(EXESUFFIX) \ $(BINDIR)/crashexport$(EXESUFFIX) \ $(BINDIR)/crashlistout$(EXESUFFIX) $(BINDIR)/crashmail$(EXESUFFIX) : $(CMOBJS) $(SHOBJS) $(NLOBJS) $(MBOBJS) $(OSLIB) $(CC) -o $(BINDIR)/crashmail$(EXESUFFIX) $(CMOBJS) $(SHOBJS) $(NLOBJS) $(MBOBJS) $(OSLIB) $(STRIP) $(BINDIR)/crashmail$(EXESUFFIX) $(BINDIR)/crashstats$(EXESUFFIX) : tools/crashstats.c $(SHOBJS) $(OSLIB) $(CC) -o $(BINDIR)/crashstats$(EXESUFFIX) tools/crashstats.c $(SHOBJS) $(OSLIB) $(STRIP) $(BINDIR)/crashstats$(EXESUFFIX) $(BINDIR)/crashlist$(EXESUFFIX) : tools/crashlist.c $(SHOBJS) $(OSLIB) $(CC) -o $(BINDIR)/crashlist$(EXESUFFIX) tools/crashlist.c $(SHOBJS) $(OSLIB) $(STRIP) $(BINDIR)/crashlist$(EXESUFFIX) $(BINDIR)/crashgetnode$(EXESUFFIX) : tools/crashgetnode.c $(SHOBJS) $(CMNLLIB) $(OSLIB) $(CC) -o $(BINDIR)/crashgetnode$(EXESUFFIX) tools/crashgetnode.c $(SHOBJS) $(CMNLLIB) $(OSLIB) $(STRIP) $(BINDIR)/crashgetnode$(EXESUFFIX) $(BINDIR)/crashmaint$(EXESUFFIX) : tools/crashmaint.c $(SHOBJS) $(OSLIB) $(JAMLIB) $(CC) -o $(BINDIR)/crashmaint$(EXESUFFIX) tools/crashmaint.c $(SHOBJS) $(OSLIB) $(JAMLIB) $(STRIP) $(BINDIR)/crashmaint$(EXESUFFIX) $(BINDIR)/crashwrite$(EXESUFFIX) : tools/crashwrite.c $(SHOBJS) $(OSLIB) $(CC) -o $(BINDIR)/crashwrite$(EXESUFFIX) tools/crashwrite.c $(SHOBJS) $(OSLIB) $(STRIP) $(BINDIR)/crashwrite$(EXESUFFIX) $(BINDIR)/crashexport$(EXESUFFIX) : tools/crashexport.c $(SHOBJS) $(OSLIB) $(CC) -o $(BINDIR)/crashexport$(EXESUFFIX) tools/crashexport.c $(SHOBJS) $(OSLIB) $(STRIP) $(BINDIR)/crashexport$(EXESUFFIX) $(BINDIR)/crashlistout$(EXESUFFIX) : tools/crashlistout.c $(SHOBJS) $(OSLIB) $(CC) -o $(BINDIR)/crashlistout$(EXESUFFIX) tools/crashlistout.c $(SHOBJS) $(OSLIB) $(STRIP) $(BINDIR)/crashlistout$(EXESUFFIX) # crashmail $(OBJDIR)/crashmail.o : crashmail/crashmail.c $(CC) -c crashmail/crashmail.c -o $(OBJDIR)/crashmail.o $(OBJDIR)/logwrite.o : crashmail/logwrite.c $(CC) -c crashmail/logwrite.c -o $(OBJDIR)/logwrite.o $(OBJDIR)/dupe.o : crashmail/dupe.c $(CC) -c crashmail/dupe.c -o $(OBJDIR)/dupe.o $(OBJDIR)/stats.o : crashmail/stats.c $(CC) -c crashmail/stats.c -o $(OBJDIR)/stats.o $(OBJDIR)/misc.o : crashmail/misc.c $(CC) -c crashmail/misc.c -o $(OBJDIR)/misc.o $(OBJDIR)/safedel.o : crashmail/safedel.c $(CC) -c crashmail/safedel.c -o $(OBJDIR)/safedel.o $(OBJDIR)/toss.o : crashmail/toss.c $(CC) -c crashmail/toss.c -o $(OBJDIR)/toss.o $(OBJDIR)/scan.o : crashmail/scan.c $(CC) -c crashmail/scan.c -o $(OBJDIR)/scan.o $(OBJDIR)/pkt.o : crashmail/pkt.c $(CC) -c crashmail/pkt.c -o $(OBJDIR)/pkt.o $(OBJDIR)/memmessage.o : crashmail/memmessage.c $(CC) -c crashmail/memmessage.c -o $(OBJDIR)/memmessage.o $(OBJDIR)/handle.o : crashmail/handle.c $(CC) -c crashmail/handle.c -o $(OBJDIR)/handle.o $(OBJDIR)/node4dpat.o : crashmail/node4dpat.c $(CC) -c crashmail/node4dpat.c -o $(OBJDIR)/node4dpat.o $(OBJDIR)/config.o : crashmail/config.c $(CC) -c crashmail/config.c -o $(OBJDIR)/config.o $(OBJDIR)/outbound.o : crashmail/outbound.c $(CC) -c crashmail/outbound.c -o $(OBJDIR)/outbound.o $(OBJDIR)/areafix.o : crashmail/areafix.c $(CC) -c crashmail/areafix.c -o $(OBJDIR)/areafix.o $(OBJDIR)/filter.o : crashmail/filter.c $(CC) -c crashmail/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 : crashmail/mb.c $(CC) -c crashmail/mb.c -o $(OBJDIR)/mb.o $(OBJDIR)/mb_msg.o : crashmail/mb_msg.c $(CC) -c crashmail/mb_msg.c -o $(OBJDIR)/mb_msg.o $(OBJDIR)/mb_jam.o : crashmail/mb_jam.c $(CC) -c crashmail/mb_jam.c -o $(OBJDIR)/mb_jam.o # nl $(OBJDIR)/nl.o : crashmail/nl.c $(CC) -c crashmail/nl.c -o $(OBJDIR)/nl.o $(OBJDIR)/nl_cmnl.o : crashmail/nl_cmnl.c $(CC) -c crashmail/nl_cmnl.c -o $(OBJDIR)/nl_cmnl.o $(OBJDIR)/nl_v7p.o : crashmail/nl_v7p.c $(CC) -c crashmail/nl_v7p.c -o $(OBJDIR)/nl_v7p.o # Clean clean : $(RM) $(OBJDIR)/*.o crashmail-0.71/src/Makefile.win320100644000000000000000000001367507762407014015316 0ustar rootroot# Makefile for Linux # General PLATFORMDEF = -DPLATFORM_WIN32 EXESUFFIX = .exe BINDIR = ../bin OBJDIR = obj INCDIR = ./ OSLIB = oslib_win32/oslib.a JAMLIB = 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) # Sum them up. Only include the messagebases you want to use MBDEFS = $(MBDEFS_MSG) $(MBDEFS_JAM) MBOBJS = $(MBOBJS_MSG) $(MBOBJS_JAM) DEFS = $(PLATFORMDEF) $(MBDEFS) $(NLDEFS) # Commands CC = gcc $(DEFS) -I $(INCDIR) -Wall RM = del 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)/crashmail.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)/crashmail$(EXESUFFIX) \ $(BINDIR)/crashstats$(EXESUFFIX) \ $(BINDIR)/crashlist$(EXESUFFIX) \ $(BINDIR)/crashgetnode$(EXESUFFIX) \ $(BINDIR)/crashmaint$(EXESUFFIX) \ $(BINDIR)/crashwrite$(EXESUFFIX) \ $(BINDIR)/crashexport$(EXESUFFIX) \ $(BINDIR)/crashlistout$(EXESUFFIX) $(BINDIR)/crashmail$(EXESUFFIX) : $(CMOBJS) $(SHOBJS) $(NLOBJS) $(MBOBJS) $(OSLIB) $(CC) -o $(BINDIR)/crashmail$(EXESUFFIX) $(CMOBJS) $(SHOBJS) $(NLOBJS) $(MBOBJS) $(OSLIB) $(STRIP) $(BINDIR)/crashmail$(EXESUFFIX) $(BINDIR)/crashstats$(EXESUFFIX) : tools/crashstats.c $(SHOBJS) $(OSLIB) $(CC) -o $(BINDIR)/crashstats$(EXESUFFIX) tools/crashstats.c $(SHOBJS) $(OSLIB) $(STRIP) $(BINDIR)/crashstats$(EXESUFFIX) $(BINDIR)/crashlist$(EXESUFFIX) : tools/crashlist.c $(SHOBJS) $(OSLIB) $(CC) -o $(BINDIR)/crashlist$(EXESUFFIX) tools/crashlist.c $(SHOBJS) $(OSLIB) $(STRIP) $(BINDIR)/crashlist$(EXESUFFIX) $(BINDIR)/crashgetnode$(EXESUFFIX) : tools/crashgetnode.c $(SHOBJS) $(CMNLLIB) $(OSLIB) $(CC) -o $(BINDIR)/crashgetnode$(EXESUFFIX) tools/crashgetnode.c $(SHOBJS) $(CMNLLIB) $(OSLIB) $(STRIP) $(BINDIR)/crashgetnode$(EXESUFFIX) $(BINDIR)/crashmaint$(EXESUFFIX) : tools/crashmaint.c $(SHOBJS) $(OSLIB) $(JAMLIB) $(CC) -o $(BINDIR)/crashmaint$(EXESUFFIX) tools/crashmaint.c $(SHOBJS) $(OSLIB) $(JAMLIB) $(STRIP) $(BINDIR)/crashmaint$(EXESUFFIX) $(BINDIR)/crashwrite$(EXESUFFIX) : tools/crashwrite.c $(SHOBJS) $(OSLIB) $(CC) -o $(BINDIR)/crashwrite$(EXESUFFIX) tools/crashwrite.c $(SHOBJS) $(OSLIB) $(STRIP) $(BINDIR)/crashwrite$(EXESUFFIX) $(BINDIR)/crashexport$(EXESUFFIX) : tools/crashexport.c $(SHOBJS) $(OSLIB) $(CC) -o $(BINDIR)/crashexport$(EXESUFFIX) tools/crashexport.c $(SHOBJS) $(OSLIB) $(STRIP) $(BINDIR)/crashexport$(EXESUFFIX) $(BINDIR)/crashlistout$(EXESUFFIX) : tools/crashlistout.c $(SHOBJS) $(OSLIB) $(CC) -o $(BINDIR)/crashlistout$(EXESUFFIX) tools/crashlistout.c $(SHOBJS) $(OSLIB) $(STRIP) $(BINDIR)/crashlistout$(EXESUFFIX) # crashmail $(OBJDIR)/crashmail.o : crashmail/crashmail.c $(CC) -c crashmail/crashmail.c -o $(OBJDIR)/crashmail.o $(OBJDIR)/logwrite.o : crashmail/logwrite.c $(CC) -c crashmail/logwrite.c -o $(OBJDIR)/logwrite.o $(OBJDIR)/dupe.o : crashmail/dupe.c $(CC) -c crashmail/dupe.c -o $(OBJDIR)/dupe.o $(OBJDIR)/stats.o : crashmail/stats.c $(CC) -c crashmail/stats.c -o $(OBJDIR)/stats.o $(OBJDIR)/misc.o : crashmail/misc.c $(CC) -c crashmail/misc.c -o $(OBJDIR)/misc.o $(OBJDIR)/safedel.o : crashmail/safedel.c $(CC) -c crashmail/safedel.c -o $(OBJDIR)/safedel.o $(OBJDIR)/toss.o : crashmail/toss.c $(CC) -c crashmail/toss.c -o $(OBJDIR)/toss.o $(OBJDIR)/scan.o : crashmail/scan.c $(CC) -c crashmail/scan.c -o $(OBJDIR)/scan.o $(OBJDIR)/pkt.o : crashmail/pkt.c $(CC) -c crashmail/pkt.c -o $(OBJDIR)/pkt.o $(OBJDIR)/memmessage.o : crashmail/memmessage.c $(CC) -c crashmail/memmessage.c -o $(OBJDIR)/memmessage.o $(OBJDIR)/handle.o : crashmail/handle.c $(CC) -c crashmail/handle.c -o $(OBJDIR)/handle.o $(OBJDIR)/node4dpat.o : crashmail/node4dpat.c $(CC) -c crashmail/node4dpat.c -o $(OBJDIR)/node4dpat.o $(OBJDIR)/config.o : crashmail/config.c $(CC) -c crashmail/config.c -o $(OBJDIR)/config.o $(OBJDIR)/outbound.o : crashmail/outbound.c $(CC) -c crashmail/outbound.c -o $(OBJDIR)/outbound.o $(OBJDIR)/filter.o : crashmail/filter.c $(CC) -c crashmail/filter.c -o $(OBJDIR)/filter.o $(OBJDIR)/areafix.o : crashmail/areafix.c $(CC) -c crashmail/areafix.c -o $(OBJDIR)/areafix.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 : crashmail/mb.c $(CC) -c crashmail/mb.c -o $(OBJDIR)/mb.o $(OBJDIR)/mb_msg.o : crashmail/mb_msg.c $(CC) -c crashmail/mb_msg.c -o $(OBJDIR)/mb_msg.o $(OBJDIR)/mb_jam.o : crashmail/mb_jam.c $(CC) -c crashmail/mb_jam.c -o $(OBJDIR)/mb_jam.o # nl $(OBJDIR)/nl.o : crashmail/nl.c $(CC) -c crashmail/nl.c -o $(OBJDIR)/nl.o $(OBJDIR)/nl_cmnl.o : crashmail/nl_cmnl.c $(CC) -c crashmail/nl_cmnl.c -o $(OBJDIR)/nl_cmnl.o $(OBJDIR)/nl_v7p.o : crashmail/nl_v7p.c $(CC) -c crashmail/nl_v7p.c -o $(OBJDIR)/nl_v7p.o # Clean clean : $(RM) $(OBJDIR)/*.o