sma-1.4.orig/0000755000175000017500000000000007743463743013310 5ustar apollockapollocksma-1.4.orig/BUGS0000644000175000017500000000101707603333515013756 0ustar apollockapollock #1 Documentation. #2 Handle [more] recipient lists.. #3 syslog doesn't provide the year - SMA uses the runtime year. This may cause some problems with log files containing new year transitions. SMA should check these situations. #4 DSN (delivery status notifications) are still a problem - SMA has no way to know how many recipients there are in addition to notification recipient. In some error situations, sendmail sends the error notification also to postmaster and that may be an alias expansion... sma-1.4.orig/COPYRIGHT0000644000175000017500000000246107604524064014574 0ustar apollockapollock$Id: COPYRIGHT,v 1.1 2001/12/30 16:19:25 jt Exp $ Copyright (c) 2000 - 2003 Jarkko Turkulainen. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY JARKKO TURKULAINEN ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JARKKO TURKULAINEN BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. sma-1.4.orig/HISTORY0000644000175000017500000001447207743465711014401 0ustar apollockapollock SMA Release history ======================================== Version 1.4, 2003/10/16 * Portugese language patch, apply with "patch < contrib/portugese.diff" (Thanks Ronaldo Lazzari) * Added msgid for clog (%i) (Thanks Ed Klavins) * Fixed a bug in HTML formatted "Relay Pairs" section (Thanks Wijnand Reimink for finding out the bug..) * Feature patch from Andrew Caird. "Downcase all addresses. This is so that foo@bar.com is equivilant to FOO@BAR.Com and Foo@Bar.com and they all get counted the same in the counts." New command line option '-A' (conf file: DowncaseAddresses). * Fixed a bug with sendmail AUTH parsing (Thanks for Daniel Melanchthon) (as a side effect, postfix logs seem to get parsed also.. :-) * Do not cut lines in status/rejected sections of ascii report (Suggested by Jeff Bronson) Version 1.3.2, 2002/12/06 * Added a legal section in README * Disabled ShowUsers in sma.conf * Flush output stream when printing clog (Suggested by Jurgen Schneider) Version 1.3.1, 2002/10/29 * Fixed a month incement bug in clog %m (Thanks Patrick Vande Walle for finding out the bug) Version 1.3, 2002/09/20 * Fixed a bug in parse() that discarded recipients in a multi-recipient message if the reporting mode was clog (pointed out by Guillermo Torres) * Support for bigger log files (Thanks Mario Pino Uceda for patch) * Fixed a bug that set the number of relays as 0 if command line option -L was defined (missing "break" statement in getopt loop) * New command line option (-t) for adjusting internal hash table size * New command line option (-D) for setting StartTime and EndTime (Thanks Alan Cheng for idea) * New command line option (-p) for dumping configuration to stdout * New command line option (-i, conf file: IncludeAscii) for including ASCII report as HTML comment (Suggested by Cove Schneider) * Print usage() to stdout (instead of stderr) for easier piping * Removed unused variables in get_string() * Support for RPM building (Thanks Stephane Lentz for spec-file) * More verbose debugging * Added a directory for user contributed software Version 1.2, 2002/07/01 * Fixed month increment error inStartTime and EndTime config file options (Thanks Igor Jovanovic for finding out the bug) * Additional error checking in conv_time() * Report memory allocation failures with errno Version 1.1, 2002/03/30 * New analysis options: - status messages (configuration file option: PrintStatus) - ruleset rejections (PrintRuleset and PrintRuleset) - top envelope pairs (EnvelopePairs) - top relay pairs (RelayPairs) * New HISTORY file format * Excellent code cleanup patch from Dirk Meyer: - strict use of "const" - use of "unsigned" (qsort needs it) - rename optind and optarg, as it conflicts with "stdutil.h" here (getopt funtion is in BSD included) - fixed bad/duplicate protoypes - removed misspelled: void htlm(FILE *); - removed extra cast: (double)atoi(); Version 1.0 2002/03/15 * Bug fixes, small corrections, etc. Version 0.19.3, 2001/12/21 * Fixed a major bug that caused sma to crash with some non-standard syslog lines. * Enchanced debug messages. Version 0.19.2, 2001/12/15 * Bug fixes. * SunOS 5.x syslogd ID generation detection. * More documentation. * More usable error messages. Version 0.19.1, 2001/12/04 * Bug fixes. Version 0.19.0, 2001/11/13 * New output format - Custom Log format (clog). * Converted man pages as PS/PDF. Version 0.18.0, 2001/11/05 * Added BgColor configuration file option. * Removed the syslog tag checking if not invoked with command line option (-L). * Various small fixes and corrections. Version 0.17.4, 2001/10/29 * Fixed #include bug. FreeBSD compiles now with USE_REGEXP. * Added "docs" directory and man pages sma.8 and re_format.7. * Fixed Makefiles. Version 0.17.3, 2001/10/26 * Regexp support for Win32. Version 0.17.2, 2001/10/25 * Fixed some stupid malloc() and strdup() bugs. Now slightly faster and a LOT more smaller. Version 0.17.1, 2001/10/24 * Removed some strange casts. * Replaced obsolent bzero() with memset(). Version 0.17.0, 2001/10/23 * Reverse filtering. * Regular expression support for Linux/BSD/SVR4. Version 0.16.2, 2001/10/19 * HTML enchancements. * SYSERR bug fix - Thanks Miroslav Zubcic for pointing it out. Version 0.16.1, 2001/10/18 * Fixed envelope counter bug. Version 0.16.0, 2001/10/16 * Initial message filtering code. * Bug fixes. * Moved compile time configurations to config.h. * DOG SLOW AGAIN.. :-) Version 0.15.1, 2001/10/11 * Makefile for MS Visual C++. * Default configuration file location. Version 0.15.0, 2001/10/10 * New log format - Sendmail for NT. * Added a copyright notice command line option (-c). * Bug fixes... Version 0.14.1, 2001/10/08 * Bug fixes. * Support for win32. Version 0.14.0, 2001/10/05 * Added command line options (-f, -o and -b). * Bug fixes * some minor modifications to ascii report. Version 0.13.0, 2001/09/24 * Changed the collecting algorithm, now based on message ids. * Removed the program delivery stuff introduced with 0.12.0. * A new debug (-v) command line option. * HTML now conforms to W3C 4.01 Version 0.12.1, 2001/08/09 * Fixed address parsing bug. * Fine tuned the ascii report. Version 0.12.0, 2001/08/08 * Changed the handling of addresses in case of program delivery. * Added ASCII output format and "-w" command line option for HTML printing. Version 0.11.0, 2001/01/01 * Added banwidth usage for senders/receivers. * Changed error messages * added a "help" command line option. Version 0.10.1, 2000/11/14 * Fixed serious address parsing bugs. Version 0.10.0, 2000/11/10 * Added relay hosts and few command line options. Version 0.9.8, 2000/09/30 * Changed sorting algorithm, now works with Linux. Version 0.9.7, 2000/08/16 * Fixed getopt(3) bug * Removed useless manpage. Version 0.9.6, 2000/08/12 * Fixed bug with the message size overflow. Version 0.9.5, 2000/08/05 * Cleaned the messy html. * Added man page. Version 0.9.4, 2000/07/06 * Fixed date bug. * Initial public release. Version 0.9.3, 2000/07/01 * Found the hot spot! now about 4 times faster. Version 0.9.2, 2000/06/26 * Fine tuning * fixed bug with file opening. * DOG SLOW. Version 0.9.1, 2000/06/25 * Fixed warning messages. Version 0.9.0, 2000/06/24 * LOTS of bug fixes * major version number jump. Version 0.1.0, 2000/06/21 * Initial release * Added this history file... sma-1.4.orig/Makefile0000644000175000017500000000100307603333515014726 0ustar apollockapollock# # $Id: Makefile,v 1.3 2001/10/29 10:24:37 jt Exp $ # BINDIR = /usr/local/bin MANDIR = /usr/local/man/man8 CC = gcc # XPG3 regular expressions (GNU/BSD/SVR4) CFLAGS = -Wall -O -DUSE_REGEXP # Others #CFLAGS = -Wall -O MAN = sma.8 PROG = sma OBJS = sma.o getopt.o parse.o utils.o hash.o html.o ascii.o init.o $(PROG): $(OBJS) $(CC) $(CFLAGS) -o $(PROG) $(OBJS) cp docs/$(MAN) . clean: rm -f $(PROG) $(PROG).exe $(OBJS) $(MAN) core install: ./install-sh $(PROG) $(BINDIR) ./install-sh $(MAN) $(MANDIR) sma-1.4.orig/Makefile.msvcp0000644000175000017500000000121107603333515016056 0ustar apollockapollock# # $Id: Makefile.msvcp,v 1.1 2001/10/26 07:54:37 jt Exp $ # # Makefile.msvcp -- makefile for MS Visual C++ # Use the nmake utility provided with the compiler # BINDIR = C:\sma CC = cl CFLAGS = -I./regex -DUSE_REGEXP PROG = sma.exe OBJS = sma.obj getopt.obj parse.obj utils.obj hash.obj html.obj \ ascii.obj init.obj regex/regcomp.obj regex/regexec.obj \ regex/regfree.obj regex/regerror.obj $(PROG): $(OBJS) $(CC) $(CFLAGS) -o $(PROG) sma.obj getopt.obj parse.obj \ utils.obj hash.obj html.obj ascii.obj init.obj regcomp.obj \ regexec.obj regfree.obj regerror.obj clean: del $(PROG) del *.obj install: copy $(PROG) $(BINDIR) sma-1.4.orig/Makefile.w320000644000175000017500000000070707603333515015352 0ustar apollockapollock# # $Id: Makefile.w32,v 1.2 2001/10/29 10:14:37 jt Exp $ # # Makefile.w32 -- makefile for mingw # BINDIR = C:\sma CC = gcc CFLAGS = -Wall -O -I./regex -DUSE_REGEXP PROG = sma OBJS = sma.o getopt.o parse.o utils.o hash.o html.o ascii.o init.o \ regex/regcomp.o regex/regexec.o regex/regfree.o regex/regerror.o $(PROG): $(OBJS) $(CC) $(CFLAGS) -o $(PROG) $(OBJS) clean: del $(PROG).exe del *.o del regex\*.o install: copy $(PROG) $(BINDIR) sma-1.4.orig/README0000644000175000017500000003177207642602653014173 0ustar apollockapollock# # Copyright (c) 2000, 2001, 2002 Jarkko Turkulainen. All rights reserved. # # SMA is copyrighted software. See the file COPYRIGHT which can be found # at the top level of the sma distribution. # # $Id: README,v 1.8.1 2003/04/02 18:45:33 jt Exp $ # SMA - SENDMAIL LOG ANALYSER PLEASE READ THIS CAREFULLY BEFORE YOU START USING THIS SOFTWARE In many countries, including Finland and many other European countries, it might be illegal to read mail logs and produce mail log summaries. Or, at least, it is illegal to use mail logs for anything else but problem solving. Of course, if you run a mail service of your own, nobody's interested in what you do with your logs. But on the other hand, if you run a mail service that is used by other persons (no matter how many) you simply cannot publish the names and top lists. You cannot even show the report to your clients!! If you are not sure about the law in your country, make sure that you run SMA always with command line option (-d) or configuration file keyword "ShowUsers no" (default in 1.3.2 or later). Or even better, disable all the envelope analyses. 1. OVERVIEW SMA is a program than analyses mail log files and produces a nice summary of mail activity. It works by taking its input from files or standard input and outputting the results to standard output or file. All error messages and debugging information are printed to standard error. Starting as of version 0.12.0, SMA prints the results as a nifty formatted ASCII report. The HTML report can still be produced with the command line option (-w). The HTML report uses heavily tables, so lynx is not the best browser for the job. If you MUST use a text browser, try using links instead. Recent SMA versions (1.3.3+) also support postix logs. At least the following features work: * Envelope senders/recipients/relays * Status messages * Time distribution 2. SOURCE INSTALLATION Unpack the distribution. Copy one of the Makefiles (Makefile, Makefile.w32 or Makefile.mscp) as Makefile. Modify Makefile and conf.h as needed. Type $ make (or nmake or gmake or whatever your system requires).. at the top level of the distribution. After successful compilation, just copy the binary file sma to your favourite directory or type # make install as root. This also installs the manpage as MANPATH/sma.8. You can also copy the default configuration file "sma.conf" as defined in conf.h. The program is small and simple, and it should compile on most UNIX-style environments. At least following systems are known to be working: AIX 4.1.3, 4.3 (gcc) Digital Unix 4.0 (gcc, DECcc) FreeBSD/i386 3.4, 3.5.1, 4.x (gcc) HP-UX 10.20 (gcc, HPcc) IRIX 6.5 (gcc) NetBSD/sparc 1.4.2 (gcc) OpenBSD/i386 2.7 - 3.2 (gcc) Red Hat Linux 5.2 - 7.2 (gcc) Solaris 2.5.1, 2.6, 7 and 8 (gcc) Solaris/i386 8 (gcc) Mac OS X (Darwin 6.2) Win32 (cygwin-1.3.3) Win32 (mingw-1.1) (*) Win32 (MS Visual C++) (**) (*) Compile with Makefile.w32 (**) Compile with Makefile.msvcp Systems with known problems: o on Tru64 UNIX cluster (DECcc) malloc() returns errno 22 (EINVAL) which indicates that the requested space is out of range. The flag -DUSE_REGEXP in CFLAGS may introduce some problems with systems not conforming to XPG3 definition of regular expressions. In that case, modify Makefile and try to recompile. If USE_REGEXP is not defined, the standard strstr() function is used with filtering routines. RPM BUILDING The RPM spec-file (contrib/sma.spec) can be used to compile RPM binary package. Here are the instructions: - Copy sma-x.tar.gz to /usr/src/RPM/SOURCES/ (x refers to sma version, for example 1.3) - Unpack sma-x.tar.gz $ tar zxvf sma-x.tar.gz - Build RPM # rpm -bb sma-x/contrib/sma.spec - Install RPM from /usr/src/RPM/RPMS/ Note that you may need to replace /usr/src/RPM with /usr/src/redhat on some Red Hat -based systems. 3. WIN32 BINARY INSTALLATION Win32 binary distribution is compiled with MinGW, see http://www.mingw.org for more information. SMA binary should run on all 32-bit Windows versions (95, 98, NT, 2000, XP, ...) that use Microsoft's standard C runtime library (MSVCRT.DLL). Here are the general instuctions on how to get SMA binary working. - Unpack the distribution sma-x-win32.zip where 'x' refers to version number of the sma distribution. - Make a directory (C:\sma etc.) If you run Sendmail for NT, it might be easiest to install the binary in that directory (C:\Program Files\Sendmail etc.) - Copy sma.exe and sma.conf to your directory. Edit sma.conf with your favourite text editor. Make sure your editor can handle ASCII files correctly. MS Word doesn't. If you run Sendmail for NT, you must enable logging to files. SMA cannot read NT event log. At Sendmail Control Panel, set sendmail logging level as '9' (or higher) and define the log file (propably C:\Program Files\Sendmail\smlog.txt or something). 4. HOW TO USE sma [-Fcdhinpsqvw] [-D date1,date2] [-b color] [-f file] [-o file] [-l num] [-r num] [-t value] [files ...] Generally, SMA reads one or more log files from /var/log (or wherever they are) and redirect the output to file. The program tries to open configuration file named "sma.conf" from the current working directory. This can be overriden with the flags (-f and -F) or with a compile time option DEFAULT_CONF, defined in file conf.h. Note that the behavior of sendmail logging has changed with the 8.12 so that the MSP and MTA deliveries are logged as a separate entries. The syslog tag should be set with the option (-L) in both sendmail and SMA. Command line options: -b color Set the background color of the HTML report as "color". This is a six-digit RGB value. -C string Set report header as "string". -c Print the copyright notice and exit. -D date1,date2 Process log entry only if the date is between "date1" and "date2". The format of the date is as follows: [[[[[cc]yy]mm]dd]HH]MM[.SS] where yy Year in abbreviated form (for years 1969-2068). The format ccyymmddHHMM is also permitted, for non-ambiguous years. mm Numeric month, a number from 1 to 12. dd Day, a number from 1 to 31. HH Hour, a number from 0 to 23. MM Minute, a number from 0 to 59. SS Second, a number from 0 to 61 (59 plus a maximum of two leap seconds). Everything but the minute is optional. The dates must be separated using a colon, without any whitespace characters. If either of the dates is missing, current date is used. -d Analyse sender/receiver domains instead of full e-mail addresses; eg. domain.com instead of joe@domain.com. -f file Read the configuration from "file" instead of the default configuration (./sma.conf). Some of the configuration options are only available from the configuration file. You should read the file "sma.conf" for more information. -F Do not use default configuration file even if it exists. -h Print help message and exit. -i Include the ASCII report in HTML comment field. This option requires HTML reporting (-w, -O html or "Format html"). -L string Process only lines with syslog tag "string". -n Do not report the time distribution. -o file Print the report as file. If not given, print to stdout. -O format Output format. ascii, html or clog. See CUSTOM LOGGING for more information on clog format. -p Print current configuration to stdout. -s Sort by transfers. Default is by number of messages. -q Do not print any warning messages. Sometimes SMA may be noisy. Use this switch if you see too many "skipping useless line.." messages. -l num Number of the senders/recipients that are printed in the summary. Default is 10. -r num Number of the input/output relay domains that are printed in the summary. Defaults to 5. -t va1ue Adjust the internal hash table size. Possible values are: "normal", "big", "huge" and custom, comma separated values. -v Print some debugging information for each parsed line. Be careful with big files and slow terminals.. -w Print the report in HTML. Examples: - Print the results in txtdocs/report.txt: $ sma maillog > txtdocs/report.txt - Print only relay domains and sort them by transfers. Output format is HTML: $ sma -nsw -l 0 maillog > wwwdocs/report.html - Print the ASCII report to file report.txt and errors/debugging to file debug.txt: $ sma -v maillog > report.txt 2> debug.txt - Read configuration from file /usr/local/etc/sma.conf and read the output file name from command line: $ sma -f /usr/local/etc/sma.conf -o report.html maillog - Read log file smlog.txt and write output to file WebUI\reports\index.html: C:\Program Files\Sendmail> sma -o WebUI\reports\index.html smlog.txt - Read from stdin and write to stdout :-) $ sma - Read only logs between minutes 15 and 45 this hour $ sma -D 15,45 maillog - Read only logs between 16:30 and 16:50 today $ sma -D 1630,1650 maillog - Read only logs before 25th day this month $ sma -D ,250000 maillog - Read only logs after 15:25:10 (hour is 15, minute 25 and second 10) $ sma -D 1525.10 maillog - Read logs between 2001 and 2002, with full dates $ sma -D 200101010000.00,200201010000.00 - Print configuration to file sma.conf $ sma -p [your favourite command line options] > sma.conf - Use big hash tables $ sma -t big - Set address hash table size as 10000 and relay table size as 3000: $ sma -t 10000,3000 5. FILTERS SMA filters help you to get an answer to questions like "how many messages are passed through a specific relay host?" or "how many messages were sent to @some.domain.com at certain time interval"? Filters are invoked from the configuration file with the following keys: Key Value --------------------------------------------------- EnvelopeSenderFilter * EnvelopeRecipientFilter * RelaySenderFilter * RelayRecipientFilter * StartTime YYYY/MM/DD-MM:HH:SS EndTime YYYY/MM/DD-MM:HH:SS The meaning of the keys should be clear - four keys are for envelopes and relays (input and ouput) and the rest of the six are for start -and end times. The values are tested as a simple substring match. Only regexp is (*) which means "any". If compiled with USE_REGEXP, all the standard, egrep-style extended regular expressions may be used. All filters are ANDed together - you cannot generate a report with filter "all mails sent to some.domain OR all mails sent from some.domain". But you can always run the same file several times with different set of filters. If complied with USE_REGEXP, filters may contain also conditionals (|). The meaning of filter can be reversed by placing '!' as a first character. All other '!'-characters are taken literally (or part of the regexp). 6. CUSTOM LOGGING Custom log format (clog) is one of the output formatting options. Unlike ASCII and HTML, which are reporting formats, clog is a sort of log file filter. It's main function is to convert the multi-line sendmail log file to a simple, one-line-per-delivery format. This simple log file may then be further analysed with another log analyzer, for example the excellent analog (http://www.statslab.cam.ac.uk/~sret1/analog). Custom logging is invoked with command line option (-O clog) and/or configured using the following configuration file keywords: Format clog ClogFormat FORMATSTRING The value FORMATSTRING controls the information and how it is formatted. It consists of ordinary characters and various two-character sequencies which are replaced with built-in variables as follows: %U time in UNIX time format %D time in form "Wed Jun 30 21:49:08 1993" %y year, four digits %m month, in digits %M month, three letter English %n minute %s second %d day %h hour %H hostname %z size in bytes %f envelope sender %t envelope recipient %F relay sender %T relay recipient %S status (1 = sent, 0 = error) %i message id %% %-character \n newline \t tab stop \\ single backslash For example, the following format string ClogFormat "%D: from=%f, to=%t, size=%z" looks at the output side like Thu Oct 25 04:24:56 2001: from=sender1, to=recipient1, size=10 Thu Oct 25 04:24:57 2001: from=sender2, to=recipient2, size=20 Thu Oct 25 04:24:58 2001: from=sender3, to=recipient3 size=30 Unlike ASCII and HTML, Custom logging is done in real-time and it runs with a very small memory footprint. Piping the output of running sendmail daemon might be a very interesting application: $ tail -f /var/log/maillog | sma -O clog 7. ACKNOWLEDGEMENTS Adam Beaumont - thanks for constructive ideas Dirk Meyer - code cleanup patch Nicos Nicolaou - ideas and feedback Mario Pino Uceda - support for big log files Pekka Honkanen - testing and feedback Stephane Lentz - RPM spec file And many others not mentioned here (see the file HISTORY) for reporting bugs, giving feedback, etc. 8. CONTACT All comments/suggestions/diffs via email to sma@klake.org sma-1.4.orig/TODO0000644000175000017500000000027107654735675014007 0ustar apollockapollock - separate sent/refused etc. in top envelope lists - fix the "year problem" (see BUGS #3) - dynamic rehashing (instead of manual -t) - (graphical?) frontend with scheduling etc.. sma-1.4.orig/ascii.c0000644000175000017500000003360607604530226014537 0ustar apollockapollock/* * sma -- Sendmail log analyser * * Copyright (c) 2000 - 2003 Jarkko Turkulainen. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY JARKKO TURKULAINEN ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL JARKKO TURKULAINEN BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $Date: 2003/01/01 13:54:00 $ */ #include "sma.h" void ascii(FILE *fp) { unsigned int j, h; char *p; struct host *hptr; const char *wdtab[] = { "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" }; const char *hrtab[] = { "00-01", "01-02", "02-03", "03-04", "04-05", "05-06", "06-07", "07-08", "08-09", "09-10", "10-11", "11-12", "12-13", "13-14", "14-15", "15-16", "16-17", "17-18", "18-19", "19-20", "20-21", "21-22", "22-23", "23-00" }; curr = localtime(&tval); p = asctime(curr); p[strlen(p)-1] = '\0'; fprintf(fp, "\n%s\n", Cchar); if (htchar) fprintf(fp, "%s\n", htchar); else fprintf(fp, "Generated at %s by SMA, version %s\n", p, VERSION); fprintf(fp, "-----------------------------------------------------------------------------\n\n"); for (hptr = first.next; hptr; hptr = hptr->next) { if (!(hptr->inum) || !(hptr->inum)) continue; fprintf(fp, "\nServer: %s\n\n", hptr->name); if (pgflag) { fprintf(fp, "General information\n"); fprintf(fp, "-----------------------------------------------------------------------------\n"); fprintf(fp, " %-33s %s", "First log entry", ctime(&hptr->ftime)); fprintf(fp, " %-33s %s", "Last log entry", ctime(&hptr->ltime)); fprintf(fp, " %-33s %d\n", "Alias table rebuilds", hptr->alias); fprintf(fp, " %-33s %d\n", "Too many hops", hptr->hopc); fprintf(fp, " %-33s %d\n", "Mail loops", hptr->lcerror); fprintf(fp, " %-33s %d\n", "Other SYSERR", hptr->oserror); fprintf(fp, " %-33s %d\n", "Ruleset based rejections", hptr->rule); fprintf(fp, " %-33s %d\n\n", "Sendmail daemon restarts", hptr->dstart); fprintf(fp, "%s%35s\n", "Inbound messages", "Outbound messages"); fprintf(fp, "-----------------------------------------------------------------------------\n"); /* * Hm. it seems that Win32 printf cannot handle correctly long's.. * This is not the right thing to do, consider some typedef instead.. * But hey, I should drop the Win32 support anyway, who uses it? */ #ifdef _WIN32 fprintf(fp, " %-20s %7d", "Total", (int)hptr->inum); fprintf(fp, " %-15s %7d\n", "Total", (int)hptr->gonum); fprintf(fp, " %-20s %7.2f", "Average size (kB)", (double)hptr->size/(double)hptr->inum/1000); #else fprintf(fp, " %-20s %7ld", "Total", hptr->inum); fprintf(fp, " %-15s %7ld\n", "Total", hptr->gonum); fprintf(fp, " %-20s %7.2Lf", "Average size (kB)", hptr->size/(double)hptr->inum/1000); #endif fprintf(fp, " %-15s %7d\n", "Sent", hptr->sent); fprintf(fp, " %-20s %7.2f", "Messages/hour", 3600*(float)hptr->inum/(float)hptr->dtime); fprintf(fp, " %-15s %7d\n", "Deferred", hptr->defe); fprintf(fp, " %-20s %7.2f", "Messages/min", 60*(float)hptr->inum/(float)hptr->dtime); fprintf(fp, " %-15s %7d\n", "Queued", hptr->queu); fprintf(fp, " %-20s %7.2f", "Messages/sec", (float)hptr->inum/(float)hptr->dtime); fprintf(fp, " %-15s %7d\n", "Other error", hptr->other + hptr->hunk + hptr->uunk + hptr->service); } if (epnum) { fprintf(fp, "\n\nTop envelope pairs\n"); fprintf(fp, "-----------------------------------------------------------------------------\n"); fprintf(fp, "%5s %-45s %6s %10s %7s\n", "Nr", "Sender/Recipient", "Msgs", "MB", "%"); fprintf(fp, "-----------------------------------------------------------------------------\n"); for (j = 0; j < (MIN(epnum, hptr->edif)); j++) { #ifdef _WIN32 fprintf(fp, "%5d %-40.40s%-5s %6d %10.2f", j+1, hptr->setab[j]->fname, (strlen(hptr->setab[j]->fname) >= 40) ? "$" : " ", hptr->setab[j]->num, (double)hptr->setab[j]->size/1000000); #else fprintf(fp, "%5d %-40.40s%-5s %6d %10.2Lf", j+1, hptr->setab[j]->fname, (strlen(hptr->setab[j]->fname) >= 40) ? "$" : " ", hptr->setab[j]->num, hptr->setab[j]->size/1000000); #endif if (sflag) { fprintf(fp, " %7.2f\n", 100*(float)hptr->setab[j]->size/(float)hptr->osize); } else { fprintf(fp, " %7.2f\n", 100*(float)hptr->setab[j]->num/(float)hptr->onum); } fprintf(fp, " %.40s%s", hptr->setab[j]->tname, (strlen(hptr->setab[j]->tname) >= 40) ? "$\n" : "\n"); } } if (lnum) { fprintf(fp, "\nTop envelope senders"); if (sef) fprintf(fp, " (filter: %s)\n", sef); else fprintf(fp, "\n"); fprintf(fp, "-----------------------------------------------------------------------------\n"); fprintf(fp, "%5s %-45s %6s %10s %7s\n", "Nr", "Sender", "Msgs", "MB", "%"); fprintf(fp, "-----------------------------------------------------------------------------\n"); for (j = 0; j < (MIN(lnum, hptr->idif)); j++) { #ifdef _WIN32 fprintf(fp, "%5d %-40.40s%-5s %6d %10.2f", j+1, hptr->sitab[j]->name, (strlen(hptr->sitab[j]->name) >= 40) ? "$" : " ", hptr->sitab[j]->num, (double)hptr->sitab[j]->size/1000000); #else fprintf(fp, "%5d %-40.40s%-5s %6d %10.2Lf", j+1, hptr->sitab[j]->name, (strlen(hptr->sitab[j]->name) >= 40) ? "$" : " ", hptr->sitab[j]->num, hptr->sitab[j]->size/1000000); #endif if (sflag) { fprintf(fp, " %7.2f\n", 100*(float)hptr->sitab[j]->size/(float)hptr->isize); } else { fprintf(fp, " %7.2f\n", 100*(float)hptr->sitab[j]->num/(float)hptr->inum); } } } if (lrnum) { fprintf(fp, "\nTop envelope recipients"); if (ref) fprintf(fp, " (filter: %s)\n", ref); else fprintf(fp, "\n"); fprintf(fp, "-----------------------------------------------------------------------------\n"); fprintf(fp, "%5s %-45s %6s %10s %7s\n", "Nr", "Recipient", "Msgs", "MB", "%"); fprintf(fp, "-----------------------------------------------------------------------------\n"); for (j = 0; j < (MIN(lrnum, hptr->odif)); j++) { #ifdef _WIN32 fprintf(fp, "%5d %-40.40s%-5s %6d %10.2f", j+1, hptr->sotab[j]->name, (strlen(hptr->sotab[j]->name) >= 40) ? "$" : " ", hptr->sotab[j]->num, (double)hptr->sotab[j]->size/1000000); #else fprintf(fp, "%5d %-40.40s%-5s %6d %10.2Lf", j+1, hptr->sotab[j]->name, (strlen(hptr->sotab[j]->name) >= 40) ? "$" : " ", hptr->sotab[j]->num, hptr->sotab[j]->size/1000000); #endif if (sflag) { fprintf(fp, " %7.2f\n", 100*(float)hptr->sotab[j]->size/(float)hptr->osize); } else { fprintf(fp, " %7.2f\n", 100*(float)hptr->sotab[j]->num/(float)hptr->onum); } } } if (rpnum) { fprintf(fp, "\n\nTop relay pairs\n"); fprintf(fp, "-----------------------------------------------------------------------------\n"); fprintf(fp, "%5s %-45s %6s %10s %7s\n", "Nr", "Sender relay/Recipient relay", "Msgs", "MB", "%"); fprintf(fp, "-----------------------------------------------------------------------------\n"); for (j = 0; j < (MIN(rpnum, hptr->rrdif)); j++) { #ifdef _WIN32 fprintf(fp, "%5d %-40.40s%-5s %6d %10.2f", j+1, hptr->srtab[j]->fname, (strlen(hptr->srtab[j]->fname) >= 40) ? "$" : " ", hptr->srtab[j]->num, (double)hptr->srtab[j]->size/1000000); #else fprintf(fp, "%5d %-40.40s%-5s %6d %10.2Lf", j+1, hptr->srtab[j]->fname, (strlen(hptr->srtab[j]->fname) >= 40) ? "$" : " ", hptr->srtab[j]->num, hptr->srtab[j]->size/1000000); #endif if (sflag) { fprintf(fp, " %7.2f\n", 100*(float)hptr->srtab[j]->size/(float)hptr->osize); } else { fprintf(fp, " %7.2f\n", 100*(float)hptr->srtab[j]->num/(float)hptr->onum); } fprintf(fp, " %.40s%s", hptr->srtab[j]->tname, (strlen(hptr->srtab[j]->tname) >= 40) ? "$\n" : "\n"); } } if (rnum) { fprintf(fp, "\nTop relay addresses, sender"); if (srf) fprintf(fp, " (filter: %s)\n", srf); else fprintf(fp, "\n"); fprintf(fp, "-----------------------------------------------------------------------------\n"); fprintf(fp, "%5s %-45s %6s %10s %7s\n", "Nr", "Relay", "Msgs", "MB", "%"); fprintf(fp, "-----------------------------------------------------------------------------\n"); for (j = 0; j < (MIN(rnum, hptr->ridif)); j++) { #ifdef _WIN32 fprintf(fp, "%5d %-40.40s%-5s %6d %10.2f", j+1, hptr->rsitab[j]->name, (strlen(hptr->rsitab[j]->name) >= 40) ? "$" : " ", hptr->rsitab[j]->num, (double)hptr->rsitab[j]->size/1000000); #else fprintf(fp, "%5d %-40.40s%-5s %6d %10.2Lf", j+1, hptr->rsitab[j]->name, (strlen(hptr->rsitab[j]->name) >= 40) ? "$" : " ", hptr->rsitab[j]->num, hptr->rsitab[j]->size/1000000); #endif if (sflag) { fprintf(fp, " %7.2f\n", 100*(float)hptr->rsitab[j]->size/(float)hptr->isize); } else { fprintf(fp, " %7.2f\n", 100*(float)hptr->rsitab[j]->num/(float)hptr->rinum); } } } if (rrnum) { fprintf(fp, "\nTop relay addresses, recipient"); if (rrf) fprintf(fp, " (filter: %s)\n", rrf); else fprintf(fp, "\n"); fprintf(fp, "-----------------------------------------------------------------------------\n"); fprintf(fp, "%5s %-45s %6s %10s %7s\n", "Nr", "Relay", "Msgs", "MB", "%"); fprintf(fp, "-----------------------------------------------------------------------------\n"); for (j = 0; j < (MIN(rrnum, hptr->rodif)); j++) { #ifdef _WIN32 fprintf(fp, "%5d %-40.40s%-5s %6d %10.2f", j+1, hptr->rsotab[j]->name, (strlen(hptr->rsotab[j]->name) >= 40) ? "$" : " ", hptr->rsotab[j]->num, (double)hptr->rsotab[j]->size/1000000); #else fprintf(fp, "%5d %-40.40s%-5s %6d %10.2Lf", j+1, hptr->rsotab[j]->name, (strlen(hptr->rsotab[j]->name) >= 40) ? "$" : " ", hptr->rsotab[j]->num, hptr->rsotab[j]->size/1000000); #endif if (sflag) { fprintf(fp, " %7.2f\n", 100*(float)hptr->rsotab[j]->size/(float)hptr->osize); } else { fprintf(fp, " %7.2f\n", 100*(float)hptr->rsotab[j]->num/(float)hptr->ronum); } } } if (stnum) { fprintf(fp, "\n\nTop status messages\n"); fprintf(fp, "-----------------------------------------------------------------------------\n"); fprintf(fp, "%5s %7s %6s %s\n", "Nr", "Msgs", "%", " Status"); fprintf(fp, "-----------------------------------------------------------------------------\n"); for (j = 0; j < (MIN(stnum, hptr->sdif)); j++) { fprintf(fp, "%5d %7d %6.2f %s %-52s\n", j+1, hptr->ssttab[j]->num, 100*(float)hptr->ssttab[j]->num/(float)hptr->onum, " ", hptr->ssttab[j]->name); } } if (rsnum) { fprintf(fp, "\n\nTop ruleset rejections\n"); fprintf(fp, "-----------------------------------------------------------------------------\n"); fprintf(fp, "%5s %7s %6s %s\n", "Nr", "Msgs", "%", rsrnum ? " Reason / Top relays" : " Reason"); fprintf(fp, "-----------------------------------------------------------------------------\n"); for (j = 0; j < (MIN(rsnum, hptr->rdif)); j++) { fprintf(fp, "%5d %7d %6.2f %s %-52s\n", j+1, hptr->sruletab[j]->num, 100*(float)hptr->sruletab[j]->num/(float)hptr->rule, " ", hptr->sruletab[j]->name); if (rsrnum) { fprintf(fp, " ------------------------------------------------------------------------\n"); for (h = 0; h < (MIN(rsrnum, hptr->sruletab[j]->reldif)); h++) { fprintf(fp, "%13d %6.2f %s %s\n", hptr->sruletab[j]->srrelaytab[h]->num, 100*(float)hptr->sruletab[j]->srrelaytab[h]->num/(float)hptr->sruletab[j]->num, " ", hptr->sruletab[j]->srrelaytab[h]->name); } fprintf(fp, "\n"); } } } if (!nflag) { fprintf(fp, "\n\n%s%42s\n", "Inbound messages per day", "Outbound messages per day"); fprintf(fp, "-----------------------------------------------------------------------------\n"); fprintf(fp, "%s %-9s %9s %9s %10s %-9s %9s %9s\n", " ", "Day", "Total", "Average", " ", "Day", "Total", "Average"); fprintf(fp, "-----------------------------------------------------------------------------\n"); for (j = 0; j < 7; j++) { if (hptr->idd[j]) fprintf(fp, "%s %-9s %9d %9.2f %10s %-9s %9d %9.2f\n", " ", wdtab[j], hptr->idd[j], hptr->fidd[j], " ", wdtab[j], hptr->odd[j], hptr->fodd[j]); } fprintf(fp, "\n\n%s%42s\n", "Inbound messages per hour", "Outbound messages per hour"); fprintf(fp, "-----------------------------------------------------------------------------\n"); fprintf(fp, "%s %-9s %9s %9s %10s %-9s %9s %9s\n", " ", "Hour", "Total", "Average", " ", "Hour", "Total", "Average"); fprintf(fp, "-----------------------------------------------------------------------------\n"); for (j = 0; j < 24; j++) { if (hptr->ihh[j]) { fprintf(fp, "%s %-9s %9d %9.2f %10s %-9s %9d %9.2f\n", " ", hrtab[j], hptr->ihh[j], hptr->fihh[j], " ", hrtab[j], hptr->ohh[j], hptr->fohh[j]); } } } } fprintf(fp, "\n\n-----------------------------------------------------------------------------\n"); if (ftchar) fprintf(fp, "%s\n", ftchar); else fprintf(fp, "Copyright (c) 2000 - 2003 Jarkko Turkulainen." " All rights reserved.\n"); } sma-1.4.orig/conf.h0000644000175000017500000000260707603333515014377 0ustar apollockapollock/* * conf.h -- compile time SMA configuration * All but DEFAULT_CONF can be changed at runtime with command line * options (-f and -F). * * $Date: 2002/09/14 11:27:00 $ */ /* * This is a default configuration file. */ #define DEFAULT_CONF "./sma.conf" /* * Default hostname. * This is used only if the hostname cannot be defined from log files * (Sendmail for NT). */ #define HOSTNAME "mailserver" /* * Bounce address and host. These are used for DSN and other error * messages as a envelope sender/relay host. */ #define BOUNCE_ADDR "MAILER-DAEMON" #define BOUNCE_HOST "localhost" /* * Default header for report */ #define COMMENT "Sendmail Log Analysis Report" /* * Defaults for Envelope senders/recipients and Relays */ #define LDEF 10 /* Envelope sender */ #define LRDEF 10 /* Envelope recipient */ #define RDEF 5 /* Relay sender */ #define RRDEF 5 /* Relay recipient */ /* * HTML defaults */ #define BG_COLOR "FFFFFF" /* Background color */ #define TB_COLOR "CCCCCC" /* Table border color */ #define PICTURE_ALT "Logo" /* ALT for HTML picture */ /* * Reasonable defaults for internal hash table size. */ #define ASIZE_NORMAL 1699 /* Address table */ #define RSIZE_NORMAL 101 /* Relay table */ #define ASIZE_BIG 30011 /* Address table */ #define RSIZE_BIG 1783 /* Relay table */ #define ASIZE_HUGE 100003 /* Address table */ #define RSIZE_HUGE 5953 /* Relay table */ sma-1.4.orig/contrib/0000755000175000017500000000000007743465604014746 5ustar apollockapollocksma-1.4.orig/contrib/mailwrapper.sh0000755000175000017500000000070107603333514017613 0ustar apollockapollock#!/bin/sh # # mailwrapper.sh -- send SMA HTML report via email # NOTE: requires "IncludeAscii yes" (cmd line: -i) # # Usage: mailwrapper.sh < report-with-ascii-comment.html # # Mail headers FROM=from@example.dom TO=to@example.dom SUBJECT="Sendmail log analysis" # Sendmail command line SENDMAIL="/usr/sbin/sendmail -t $TO" ( echo From: $FROM echo To: $TO echo Subject: $SUBJECT echo sed -n '//p' | egrep -v '^' ) | $SENDMAIL sma-1.4.orig/contrib/portugues.patch0000644000175000017500000010005207743465604020022 0ustar apollockapollockdiff -r -u ./ascii.c ../sma-1.4.portugues/ascii.c --- ./ascii.c Wed Jan 1 11:10:46 2003 +++ ../sma-1.4.portugues/ascii.c Mon Oct 13 21:25:11 2003 @@ -55,28 +55,28 @@ if (htchar) fprintf(fp, "%s\n", htchar); else - fprintf(fp, "Generated at %s by SMA, version %s\n", + fprintf(fp, "Gerado em %s pelo SMA, versão %s\n", p, VERSION); fprintf(fp, "-----------------------------------------------------------------------------\n\n"); for (hptr = first.next; hptr; hptr = hptr->next) { if (!(hptr->inum) || !(hptr->inum)) continue; - fprintf(fp, "\nServer: %s\n\n", hptr->name); + fprintf(fp, "\nServidor: %s\n\n", hptr->name); if (pgflag) { - fprintf(fp, "General information\n"); + fprintf(fp, "Informações Gerais\n"); fprintf(fp, "-----------------------------------------------------------------------------\n"); - fprintf(fp, " %-33s %s", "First log entry", ctime(&hptr->ftime)); - fprintf(fp, " %-33s %s", "Last log entry", ctime(&hptr->ltime)); - fprintf(fp, " %-33s %d\n", "Alias table rebuilds", hptr->alias); - fprintf(fp, " %-33s %d\n", "Too many hops", hptr->hopc); - fprintf(fp, " %-33s %d\n", "Mail loops", hptr->lcerror); - fprintf(fp, " %-33s %d\n", "Other SYSERR", hptr->oserror); - fprintf(fp, " %-33s %d\n", "Ruleset based rejections", hptr->rule); - fprintf(fp, " %-33s %d\n\n", "Sendmail daemon restarts", hptr->dstart); + fprintf(fp, " %-48s %s", "Primeira entrada do log", ctime(&hptr->ftime)); + fprintf(fp, " %-48s %s", "Última entrada do log", ctime(&hptr->ltime)); + fprintf(fp, " %-48s %d\n", "Rebuilds da tabela de alias", hptr->alias); + fprintf(fp, " %-48s %d\n", "Hops em demasia", hptr->hopc); + fprintf(fp, " %-48s %d\n", "Loops de correio", hptr->lcerror); + fprintf(fp, " %-48s %d\n", "Outros SYSERR", hptr->oserror); + fprintf(fp, " %-48s %d\n", "Rejeições baseadas em regras pré-determinadas", hptr->rule); + fprintf(fp, " %-48s %d\n\n", "Restarts do deamon do Sendmail", hptr->dstart); - fprintf(fp, "%s%35s\n", "Inbound messages", "Outbound messages"); + fprintf(fp, "%s%33s\n", "Mensagens de entrada", "Mensagens de saída"); fprintf(fp, "-----------------------------------------------------------------------------\n"); /* @@ -87,36 +87,36 @@ #ifdef _WIN32 fprintf(fp, " %-20s %7d", "Total", (int)hptr->inum); fprintf(fp, " %-15s %7d\n", "Total", (int)hptr->gonum); - fprintf(fp, " %-20s %7.2f", "Average size (kB)", + fprintf(fp, " %-20s %7.2f", "Tamanho médio (kB)", (double)hptr->size/(double)hptr->inum/1000); #else fprintf(fp, " %-20s %7ld", "Total", hptr->inum); fprintf(fp, " %-15s %7ld\n", "Total", hptr->gonum); - fprintf(fp, " %-20s %7.2Lf", "Average size (kB)", + fprintf(fp, " %-20s %7.2Lf", "Tamanho médio (kB)", hptr->size/(double)hptr->inum/1000); #endif - fprintf(fp, " %-15s %7d\n", "Sent", hptr->sent); + fprintf(fp, " %-15s %7d\n", "Enviadas", hptr->sent); - fprintf(fp, " %-20s %7.2f", "Messages/hour", + fprintf(fp, " %-20s %7.2f", "Mensagens/hora", 3600*(float)hptr->inum/(float)hptr->dtime); - fprintf(fp, " %-15s %7d\n", "Deferred", hptr->defe); + fprintf(fp, " %-15s %7d\n", "Diferidas", hptr->defe); - fprintf(fp, " %-20s %7.2f", "Messages/min", + fprintf(fp, " %-20s %7.2f", "Mensagens/min", 60*(float)hptr->inum/(float)hptr->dtime); - fprintf(fp, " %-15s %7d\n", "Queued", hptr->queu); + fprintf(fp, " %-15s %7d\n", "Em fila", hptr->queu); - fprintf(fp, " %-20s %7.2f", "Messages/sec", + fprintf(fp, " %-20s %7.2f", "Mensagens/seg", (float)hptr->inum/(float)hptr->dtime); - fprintf(fp, " %-15s %7d\n", "Other error", + fprintf(fp, " %-15s %7d\n", "Outros erros", hptr->other + hptr->hunk + hptr->uunk + hptr->service); } if (epnum) { - fprintf(fp, "\n\nTop envelope pairs\n"); + fprintf(fp, "\n\nPrincipais pares remetente/destinatário\n"); fprintf(fp, "-----------------------------------------------------------------------------\n"); - fprintf(fp, "%5s %-45s %6s %10s %7s\n", - "Nr", "Sender/Recipient", "Msgs", "MB", "%"); + fprintf(fp, "%5s %-46s %6s %5s %6s\n", + "Num", "Remetente/Destinatário", "Mensagens", "MB", "%"); fprintf(fp, "-----------------------------------------------------------------------------\n"); for (j = 0; j < (MIN(epnum, hptr->edif)); j++) { @@ -148,12 +148,12 @@ if (lnum) { - fprintf(fp, "\nTop envelope senders"); - if (sef) fprintf(fp, " (filter: %s)\n", sef); + fprintf(fp, "\nPrincipais remetentes"); + if (sef) fprintf(fp, " (filtro: %s)\n", sef); else fprintf(fp, "\n"); fprintf(fp, "-----------------------------------------------------------------------------\n"); - fprintf(fp, "%5s %-45s %6s %10s %7s\n", - "Nr", "Sender", "Msgs", "MB", "%"); + fprintf(fp, "%5s %-46s %6s %5s %6s\n", + "Num", "Remetente", "Mensagens", "MB", "%"); fprintf(fp, "-----------------------------------------------------------------------------\n"); for (j = 0; j < (MIN(lnum, hptr->idif)); j++) { @@ -182,12 +182,12 @@ } if (lrnum) { - fprintf(fp, "\nTop envelope recipients"); - if (ref) fprintf(fp, " (filter: %s)\n", ref); + fprintf(fp, "\nPrincipais destinatários"); + if (ref) fprintf(fp, " (filtro: %s)\n", ref); else fprintf(fp, "\n"); fprintf(fp, "-----------------------------------------------------------------------------\n"); - fprintf(fp, "%5s %-45s %6s %10s %7s\n", - "Nr", "Recipient", "Msgs", "MB", "%"); + fprintf(fp, "%5s %-46s %6s %5s %6s\n", + "Num", "Destinaátio", "Mensagens", "MB", "%"); fprintf(fp, "-----------------------------------------------------------------------------\n"); for (j = 0; j < (MIN(lrnum, hptr->odif)); j++) { #ifdef _WIN32 @@ -215,10 +215,10 @@ } if (rpnum) { - fprintf(fp, "\n\nTop relay pairs\n"); + fprintf(fp, "\n\nPrincipais pares de relay\n"); fprintf(fp, "-----------------------------------------------------------------------------\n"); - fprintf(fp, "%5s %-45s %6s %10s %7s\n", - "Nr", "Sender relay/Recipient relay", "Msgs", "MB", "%"); + fprintf(fp, "%5s %-46s %6s %5s %6s\n", + "Num", "Relay de remetente/Relay de destinatário", "Mensagens", "MB", "%"); fprintf(fp, "-----------------------------------------------------------------------------\n"); for (j = 0; j < (MIN(rpnum, hptr->rrdif)); j++) { @@ -249,12 +249,12 @@ if (rnum) { - fprintf(fp, "\nTop relay addresses, sender"); - if (srf) fprintf(fp, " (filter: %s)\n", srf); + fprintf(fp, "\nPrincipais endereços de relay - remetente"); + if (srf) fprintf(fp, " (filtro: %s)\n", srf); else fprintf(fp, "\n"); fprintf(fp, "-----------------------------------------------------------------------------\n"); - fprintf(fp, "%5s %-45s %6s %10s %7s\n", - "Nr", "Relay", "Msgs", "MB", "%"); + fprintf(fp, "%5s %-46s %6s %5s %6s\n", + "Num", "Relay", "Mensagens", "MB", "%"); fprintf(fp, "-----------------------------------------------------------------------------\n"); for (j = 0; j < (MIN(rnum, hptr->ridif)); j++) { @@ -284,12 +284,12 @@ } if (rrnum) { - fprintf(fp, "\nTop relay addresses, recipient"); - if (rrf) fprintf(fp, " (filter: %s)\n", rrf); + fprintf(fp, "\nPrincipais endereços de relay - destinatário"); + if (rrf) fprintf(fp, " (filtro: %s)\n", rrf); else fprintf(fp, "\n"); fprintf(fp, "-----------------------------------------------------------------------------\n"); - fprintf(fp, "%5s %-45s %6s %10s %7s\n", - "Nr", "Relay", "Msgs", "MB", "%"); + fprintf(fp, "%5s %-46s %6s %5s %6s\n", + "Num", "Relay", "Mensagens", "MB", "%"); fprintf(fp, "-----------------------------------------------------------------------------\n"); for (j = 0; j < (MIN(rrnum, hptr->rodif)); j++) { #ifdef _WIN32 @@ -316,10 +316,10 @@ } if (stnum) { - fprintf(fp, "\n\nTop status messages\n"); + fprintf(fp, "\n\nPrincipais mensagens de status\n"); fprintf(fp, "-----------------------------------------------------------------------------\n"); fprintf(fp, "%5s %7s %6s %s\n", - "Nr", "Msgs", "%", " Status"); + "Num", "Msgs", "%", " Status"); fprintf(fp, "-----------------------------------------------------------------------------\n"); for (j = 0; j < (MIN(stnum, hptr->sdif)); j++) { fprintf(fp, "%5d %7d %6.2f %s %-52s\n", j+1, @@ -330,10 +330,10 @@ } if (rsnum) { - fprintf(fp, "\n\nTop ruleset rejections\n"); + fprintf(fp, "\n\nPrincipais rejeições por regras pré-determinadas\n"); fprintf(fp, "-----------------------------------------------------------------------------\n"); fprintf(fp, "%5s %7s %6s %s\n", - "Nr", "Msgs", "%", rsrnum ? " Reason / Top relays" : " Reason"); + "Num", "Msgs", "%", rsrnum ? " Motivo / Principais relays" : " Motivo"); fprintf(fp, "-----------------------------------------------------------------------------\n"); for (j = 0; j < (MIN(rsnum, hptr->rdif)); j++) { fprintf(fp, "%5d %7d %6.2f %s %-52s\n", j+1, @@ -356,11 +356,11 @@ } if (!nflag) { - fprintf(fp, "\n\n%s%42s\n", "Inbound messages per day", "Outbound messages per day"); + fprintf(fp, "\n\n%s%42s\n", "Mensagens de entrada por dia", "Mensagens de saída por dia"); fprintf(fp, "-----------------------------------------------------------------------------\n"); fprintf(fp, "%s %-9s %9s %9s %10s %-9s %9s %9s\n", - " ", "Day", "Total", "Average", - " ", "Day", "Total", "Average"); + " ", "Dia", "Total", "Média", + " ", "Dia", "Total", "Média"); fprintf(fp, "-----------------------------------------------------------------------------\n"); for (j = 0; j < 7; j++) { if (hptr->idd[j]) @@ -369,11 +369,11 @@ " ", wdtab[j], hptr->odd[j], hptr->fodd[j]); } - fprintf(fp, "\n\n%s%42s\n", "Inbound messages per hour", "Outbound messages per hour"); + fprintf(fp, "\n\n%s%42s\n", "Mensagens de entrada por hora", "Mensagens de saída por hora"); fprintf(fp, "-----------------------------------------------------------------------------\n"); fprintf(fp, "%s %-9s %9s %9s %10s %-9s %9s %9s\n", - " ", "Hour", "Total", "Average", - " ", "Hour", "Total", "Average"); + " ", "Hora", "Total", "Média", + " ", "Hora", "Total", "Média"); fprintf(fp, "-----------------------------------------------------------------------------\n"); for (j = 0; j < 24; j++) { @@ -391,5 +391,5 @@ fprintf(fp, "%s\n", ftchar); else fprintf(fp, "Copyright (c) 2000 - 2003 Jarkko Turkulainen." - " All rights reserved.\n"); + " Todos os direitos reservados.\n"); } diff -r -u ./html.c ../sma-1.4.portugues/html.c --- ./html.c Sat Mar 22 15:31:14 2003 +++ ../sma-1.4.portugues/html.c Mon Oct 13 20:39:44 2003 @@ -59,7 +59,7 @@ " \n" " \n" " \n", VERSION); - fprintf(fp, " sendmail log analysis report\n" + fprintf(fp, " Relatório de Análise de Log do Sendmail\n" " \n\n" " \n", bchar); @@ -82,8 +82,8 @@ if (htchar) fprintf(fp, " %s\n", htchar); else - fprintf(fp, " Generated at %s by SMA, " - "version %s\n", stripn(asctime(curr)), + fprintf(fp, " Gerado em %s pelo SMA, " + "versão %s\n", stripn(asctime(curr)), VERSION); fprintf(fp, " \n" " \n" @@ -93,13 +93,13 @@ if (htchar) fprintf(fp, " %s\n", htchar); else - fprintf(fp, " Generated at %s by SMA, " - "version %s\n", stripn(asctime(curr)), + fprintf(fp, " Gerado em %s pelo SMA, " + "versão %s\n", stripn(asctime(curr)), VERSION); } fprintf(fp, "


\n\n" " \n" - "

Index

\n"); + "

Índice

\n"); for (hptr = first.next; hptr; hptr = hptr->next) { if (!(hptr->inum) || !(hptr->inum)) @@ -108,27 +108,27 @@ fprintf(fp, " %s
\n", hptr->name, hptr->name); fprintf(fp, " \n"); @@ -144,60 +144,60 @@ if (pgflag) { fprintf(fp, " \n", hptr->name); - fprintf(fp, " General information
\n" + fprintf(fp, " Informações gerais
\n" " \n" " \n" - " \n", tbchar); + " \n", tbchar); fprintf(fp, " \n", stripn(ctime(&hptr->ftime))); fprintf(fp, " \n" " \n" - " \n", tbchar); + " \n", tbchar); fprintf(fp, " \n", stripn(ctime(&hptr->ltime))); fprintf(fp, " \n" " \n" " \n", tbchar); + "Rebuilds da tabela de alias\n", tbchar); fprintf(fp, " \n", hptr->alias); fprintf(fp, " \n" " \n" " \n", tbchar); + "Hoops em demasia\n", tbchar); fprintf(fp, " \n", hptr->hopc); fprintf(fp, " \n" " \n" " \n", tbchar); + "Loops de correio\n", tbchar); fprintf(fp, " \n", hptr->lcerror); fprintf(fp, " \n" " \n" " \n", tbchar); + "Outros SYSERR\n", tbchar); fprintf(fp, " \n", hptr->oserror); fprintf(fp, " \n" " \n" " \n", tbchar); + "Rejeições baseadas em regras pré-determinadas\n", tbchar); fprintf(fp, " \n", hptr->rule); fprintf(fp, " \n" " \n" " \n", tbchar); + "Restarts do deamon do Sendmail\n", tbchar); fprintf(fp, " \n", hptr->dstart); fprintf(fp, " \n" "
First log entryPrimeira entrada do log%s
Last log entryÚltima entrada do log%s
" - "Alias table rebuilds%d
" - "Too many hops%d
" - "Mail loops%d
" - "Other SYSERR%d
" - "Ruleset based rejections%d
" - "Sendmail daemon restarts%d

\n" " \n" " \n" - " \n" - "
Inbound messages
\n" + "
Mensagens de entrada
\n" " \n" " \n" " \n", tbchar); @@ -209,7 +209,7 @@ fprintf(fp, " \n" " \n" - " \n", tbchar); + " \n", tbchar); #ifdef _WIN32 fprintf(fp, " \n", (double)hptr->size/(double)hptr->inum/1000); @@ -220,27 +220,27 @@ fprintf(fp, " \n" " \n" - " \n", tbchar); + " \n", tbchar); fprintf(fp, " \n", 3600*(float)hptr->inum/(float)hptr->dtime); fprintf(fp, " \n" " \n" - " \n", tbchar); + " \n", tbchar); fprintf(fp, " \n", 60*(float)hptr->inum/(float)hptr->dtime); fprintf(fp, " \n" " \n" - " \n", tbchar); + " \n", tbchar); fprintf(fp, " \n", (float)hptr->inum/(float)hptr->dtime); fprintf(fp, " \n" "
Total
Average size (kB)Tamanho médio (kB)%.2f
Messages/hourMensagens/hora%.2f
Messages/minMensagens/min%.2f
Messages/secMensagens/seg%.2f
\n" "
Outbound messages
\n" + "
Mensagens de saída
\n" " \n" " \n" " \n", tbchar); @@ -252,22 +252,22 @@ fprintf(fp, " \n" " \n" - " \n", tbchar); + " \n", tbchar); fprintf(fp, " \n", hptr->sent); fprintf(fp, " \n" " \n" - " \n", tbchar); + " \n", tbchar); fprintf(fp, " \n", hptr->defe); fprintf(fp, " \n" " \n" - " \n", tbchar); + " \n", tbchar); fprintf(fp, " \n", hptr->queu); fprintf(fp, " \n" " \n" - " \n", tbchar); + " \n", tbchar); fprintf(fp, " \n", hptr->other + hptr->hunk + hptr->uunk + hptr->service); fprintf(fp, " \n" @@ -275,24 +275,24 @@ " \n" " \n" "
Total
SentEnviadas%d
DeferredDiferidas%d
QueuedColocas em fila%d
Other errorOutros erros%d

\n\n" - " [Index]\n"); + " [Índice]\n"); fprintf(fp, " [%s]\n\n", hptr->name, hptr->name); } if (epnum) { fprintf(fp, " \n", hptr->name); - fprintf(fp, "

Top envelope pairs"); + fprintf(fp, "

Principais envelope pairs"); fprintf(fp, "
\n"); fprintf(fp, " \n" " \n" " \n" - " \n" + "Número\n" + " \n" " \n" + "Mensagens\n" " \n" + "Transferências (MB)\n" " \n" " \n", tbchar, tbchar, tbchar, tbchar, tbchar); @@ -320,24 +320,24 @@ } } fprintf(fp, "
" - "NumberSender/RecipientRemetente/Destinatário" - "Messages" - "Transfers (MB)" "%%

\n\n" - " [Index]\n"); + " [Índice]\n"); fprintf(fp, " [%s]\n\n", hptr->name, hptr->name); } if (lnum) { fprintf(fp, " \n", hptr->name); - fprintf(fp, "

Top envelope senders"); + fprintf(fp, "

Principais envelope senders"); if (sef) fprintf(fp, " (filter: %s)
\n", sef); else fprintf(fp, "

\n"); fprintf(fp, " \n" " \n" " \n" - " \n" + "Número\n" + " \n" " \n" + "Mensagens\n" " \n" + "Transferências (MB)\n" " \n" " \n", tbchar, tbchar, tbchar, tbchar, tbchar); @@ -366,7 +366,7 @@ } } fprintf(fp, "
" - "NumberSenderRemetente" - "Messages" - "Transfers (MB)" "%%

\n\n" - " [Index]\n"); + " [Índice]\n"); fprintf(fp, " [%s]\n\n", hptr->name, hptr->name); } @@ -374,18 +374,18 @@ if (lrnum) { fprintf(fp, " \n", hptr->name); - fprintf(fp, "

Top envelope recipients"); + fprintf(fp, "

Principais envelope recipients"); if (ref) fprintf(fp, " (filter: %s)
\n", ref); else fprintf(fp, "

\n"); fprintf(fp, " \n" " \n" " \n" - " \n" + "Números\n" + " \n" " \n" + "Mensagens\n" " \n" + "Transferências (MB)\n" " \n" " \n", tbchar, tbchar, tbchar, tbchar, tbchar); @@ -414,24 +414,24 @@ } } fprintf(fp, "
" - "NumberRecipientDestinatários" - "Messages" - "Transfers (MB)" "%%

\n\n" - " [Index]\n"); + " [Índice]\n"); fprintf(fp, " [%s]\n\n", hptr->name, hptr->name); } if (rpnum) { fprintf(fp, " \n", hptr->name); - fprintf(fp, "

Top relay pairs"); + fprintf(fp, "

Principais pares de relay"); fprintf(fp, "
\n"); fprintf(fp, " \n" " \n" " \n" - " \n" + "Número\n" + " \n" " \n" + "Mensagens\n" " \n" + "Transferências (MB)\n" " \n" " \n", tbchar, tbchar, tbchar, tbchar, tbchar); @@ -459,25 +459,25 @@ } } fprintf(fp, "
" - "NumberSender relay/Recipient relayRelay de remetente/Relay de destinatário" - "Messages" - "Transfers (MB)" "%%

\n\n" - " [Index]\n"); + " [Índice]\n"); fprintf(fp, " [%s]\n\n", hptr->name, hptr->name); } if (rnum) { fprintf(fp, " \n", hptr->name); - fprintf(fp, "

Top relay addresses, sender"); - if (srf) fprintf(fp, " (filter: %s)
\n", srf); + fprintf(fp, "

Principais endereços de relay - remetente"); + if (srf) fprintf(fp, " (filtro: %s)
\n", srf); else fprintf(fp, "

\n"); fprintf(fp, " \n" " \n" " \n" + "Número\n" " \n" " \n" + "Mensagens\n" " \n" + "Transferências (MB)\n" " \n" " \n", tbchar, tbchar, tbchar, tbchar, tbchar); @@ -505,25 +505,25 @@ fprintf(fp, " \n"); } fprintf(fp, "
" - "NumberRelay" - "Messages" - "Transfers (MB)" "%%

\n\n" - " [Index]\n"); + " [Índice]\n"); fprintf(fp, " [%s]\n\n", hptr->name, hptr->name); } if (rrnum) { fprintf(fp, " \n", hptr->name); - fprintf(fp, "

Top relay addresses, recipient"); - if (rrf) fprintf(fp, " (filter: %s)
\n", rrf); + fprintf(fp, "

Principais endereços de relay - destinatário"); + if (rrf) fprintf(fp, " (filtro: %s)
\n", rrf); else fprintf(fp, "

\n"); fprintf(fp, " \n" " \n" " \n" + "Número\n" " \n" " \n" + "Mensagens\n" " \n" + "Transferências (MB)\n" " \n" " \n", tbchar, tbchar, tbchar, tbchar, tbchar); @@ -551,19 +551,19 @@ fprintf(fp, " \n"); } fprintf(fp, "
" - "NumberRelay" - "Messages" - "Transfers (MB)" "%%

\n\n" - " [Index]\n"); + " [Índice]\n"); fprintf(fp, " [%s]\n\n", hptr->name, hptr->name); } if (stnum) { fprintf(fp, " \n", hptr->name); - fprintf(fp, "

Top status messages"); + fprintf(fp, "

Principais mensagens de status"); fprintf(fp, "
\n"); fprintf(fp, " \n" " \n" " \n" - " \n" + "Número\n" + " \n" " \n" " \n" @@ -582,24 +582,24 @@ fprintf(fp, " \n"); } fprintf(fp, "
" - "NumberMsgsMensagens%%" "Status

\n\n" - " [Index]\n"); + " [Índice]\n"); fprintf(fp, " [%s]\n\n", hptr->name, hptr->name); } if (rsnum) { fprintf(fp, " \n", hptr->name); - fprintf(fp, "

Top ruleset rejections"); + fprintf(fp, "

Principais rejeições por regras pré-determinadas"); fprintf(fp, "
\n"); fprintf(fp, " \n" " \n" " \n" - " \n" + "Número\n" + " \n" " \n" " \n" " \n", tbchar, tbchar, tbchar, tbchar, - rsrnum ? "Reason / Top relays" : "Reason"); + rsrnum ? "Motivo / Principais relays" : "motivo"); for (j = 0; j < (MIN(rsnum, hptr->rdif)); j++) { fprintf(fp, " \n"); @@ -639,7 +639,7 @@ } fprintf(fp, "
" - "NumberMsgsMensagens%%" "%s

\n\n" - " [Index]\n"); + " [Índice]\n"); fprintf(fp, " [%s]\n\n", hptr->name, hptr->name); } @@ -647,12 +647,12 @@ fprintf(fp, "

\n", hptr->name); fprintf(fp, " \n" " \n" - " \n" - "
Inbound messages per day
\n" + "
Mensagesn de entrada por dia
\n" " \n" " \n" - " \n" + " \n" " \n" - " \n" + " \n" " \n", tbchar, tbchar, tbchar); for (j = 0; j < 7; j++) { @@ -670,12 +670,12 @@ fprintf(fp, "
DayDiaTotalAverageMédia
\n" "
Outbound messages per day
\n" + "
Mensagens de saída por dia
\n" " \n" " \n" - " \n" + " \n" " \n" - " \n" + " \n" " \n", tbchar, tbchar, tbchar); for (j = 0; j < 7; j++) { @@ -696,12 +696,12 @@ "
DayDiaTotalAverageMédia

\n" " \n" " \n" - " \n" - "
Inbound messages per hour
\n" + "
Mensagens de entrada por hora
\n" " \n" " \n" - " \n" + " \n" " \n" - " \n" + " \n" " \n", tbchar, tbchar, tbchar); for (j = 0; j < 24; j++) { @@ -719,12 +719,12 @@ fprintf(fp, "
HourHoraTotalAverageMédia
\n" "
Outbound messages per hour
\n" + "
Mensagens de saída por hora
\n" " \n" " \n" - " \n" + " \n" " \n" - " \n" + " \n" " \n", tbchar, tbchar, tbchar); for (j = 0; j < 24; j++) { @@ -743,7 +743,7 @@ " \n" " \n" "
HourHoraTotalAverageMédia

\n\n" - " [Index]\n"); + " [Índice]\n"); fprintf(fp, " [%s]\n\n", hptr->name, hptr->name); } fprintf(fp, "


\n"); @@ -752,6 +752,6 @@ fprintf(fp, " %s\n", ftchar); else fprintf(fp, " Copyright (c) 2000 - 2003" - " Jarkko Turkulainen. All rights reserved.\n"); + " Jarkko Turkulainen. Todos os direitos reservados.\n"); fprintf(fp, " \n\n"); } sma-1.4.orig/contrib/sma.spec0000644000175000017500000000270607605314520016372 0ustar apollockapollock%define name sma %define version 1.3.3 %define release 1 Summary: SMA - Sendmail log analyser Name: %name Version: %version Release: %release License: BSD #Author: Jarkko Turkulainen Group: Monitoring URL: http://www.klake.org/sma/ Source: http://www.klake.org/sma/dl/%{name}-%%{version}.tar.gz BuildRoot: %{_tmppath}/%{name}-%{version}-root #BuildRoot: /var/tmp/%{name}-root Buildrequires: make gcc %description SMA - Sendmail log analyser is a program that analyses sendmail log entries. The key features of SMA are : Fast (written in C) Portable Free (BSD-style licensing) %prep rm -rf $RPM_BUILD_ROOT %setup -q %build make CFLAGS="$RPM_OPT_FLAGS" %install rm -rf $RPM_BUILD_ROOT mkdir -p $RPM_BUILD_ROOT/%{_bindir} mkdir -p $RPM_BUILD_ROOT/%{_mandir}/man8 make install BINDIR=$RPM_BUILD_ROOT/%{_bindir} MANDIR=$RPM_BUILD_ROOT/%{_mandir}/man8 mkdir -p $RPM_BUILD_ROOT/usr/share/doc/%{name}-%%{version} %files %defattr(-,root,root) %doc docs/re_format.7 docs/re_format.ps docs/sma.8 docs/sma.ps docs/re_format.pdf docs/re_format.txt docs/sma.pdf docs/sma.txt sma.conf README COPYRIGHT TODO %_bindir/sma %{_mandir}/man8/sma.8.* %changelog * Fri Jan 03 2003 Jarkko Turkulainen 1.3.3-1 - SPEC for 1.3.3 * Sat Nov 30 2002 Jarkko Turkulainen 1.3.2-1 - SPEC for 1.3.2 * Wed Aug 8 2002 Jarkko Turkulainen 1.3-1 - SPEC for 1.3 * Tue Aug 7 2002 Stephane Lentz 1.2-1mdk - first RPM SPEC sma-1.4.orig/contrib/spam-graph.pl0000644000175000017500000001747607603333514017346 0ustar apollockapollock#!/usr/local/bin/perl # blocked SPAM monthly stats # author: Dominik M Miklaszewski (dmikey@distantmoon.net) # # usage: spam-monthly.pl [-m] [date1] [date2] (using -m generates monthly stats up to date) # input: YYYYMMDD-mailstats - file generated by # '/usr/local/bin/sma -a /var/log/maillog > /var/log/$CURR_DATE-mailstats' i.e. from cronjob: # # #!/bin/sh # CURR_DATE=`/bin/date +'%Y%m%d'` # /usr/local/bin/sma -a /var/log/maillog > /var/log/$CURR_DATE-mailstats # # output: png # systems: Solaris 2.6, Solaris 2.8, Linux SuSE 7.3 # (shouldn't have problems on any others where PERL,gd and zlib-1.1.3/1.1.4 is installed) # # You need to have following PERL modules installed in your system: # GD-1.27, DateManip-5.40, MailTools-1.1401, MIME-tools-5.408 (or any other more/less recent version of each) # # This tiny script can be easily expanded to graph out some other things sma provides and I will work on it.. # If you have any questions, ideas just email me. # (Note: I know one can utilize RRD for that kind of stuff, but I didn't have enough time to learn RRD so just # grabbed some old routines I wrote two years ago and modified them for this purpose.) use GD; use Date::Manip; use MIME::Base64; use MIME::Entity; ########################################################## # path for files and other global settings # ########################################################## $document_title = "Monthly SPAM Report"; $sender = "SysAdmin\@yourdomain\.com"; $reply_to = "yourself\@yourdomain\.com"; $recipient = "yourself\@yourdomain\.com"; $cc_recipient = "any_other_aliased_recipients"; $archpath = "/arch"; $destpath = "."; $pre = ""; $post = "-mailstats"; $startdate = $ARGV[0]; $stopdate = $ARGV[1]; $storefile = $ARGV[2]; @table = (); ###################### # auxiliary settings # ###################### # ======== date butchery ================== # first conditional is based on assumption that script is gonna be run on every 1st day of the month, how stupid.. if ($ARGV[0] eq "-m") { $startdate = &DateCalc("today"," - 1 month",\$err); $stopdate = &DateCalc("today","- 1 day",\$err); $chkstopdate = substr($stopdate,2,6); $delta = &DateCalc($startdate,$stopdate,\$err); @diff = split(/:/,$delta); $delta = ($diff[2])*7+($diff[3]); } else { $startdate=&ParseDate($startdate); $stopdate=&ParseDate($stopdate); $chkstopdate = substr($stopdate,2,6); $delta=&DateCalc($startdate,$stopdate,\$err); @diff=split(/:/,$delta); $delta=($diff[2])*7+($diff[3]); } $title1 = "Monthly blocked SPAM @mailrelay2: " . &UnixDate($startdate,"%a %b %e %Y") . " until " . &UnixDate($stopdate,"%a %b %e %Y"); $headtitle = "Monthly SPAM Report for: ". &UnixDate($startdate,"%a %b %e %Y") ." until " . &UnixDate($stopdate,"%a %b %e %Y"); &html_header("$headtitle"); $startdate = &UnixDate($startdate,"%Y%m%d"); $stopdate = &UnixDate($stopdate,"%Y%m%d"); $sdate=$startdate; $testdate=$sdate; for($i=0;$i<($delta+1);$i++) { for ($a=0;$a<4;$a++){$dtrend{$trentity[$a]}=0;} $itestm = substr($testdate,2,2); $testdate=&DateCalc($sdate,"+$i day",\$err); $testdate=substr($testdate,0,8); $testm = substr($testdate,2,2); if (($testm ne $itestm) and ($itestm !="00")) { for ($a=0;$a<4;$a++){$mtrend{$trentity[$a]}=0;} $itestm=$testm; } $logfile = $testdate . $post; # the date when I started using sma for reporting - if you don't need that conditional simply replace first # 'if' condition with ($testdate) and the 'else' will never happen :) if ($testdate > 20020602) { $INPUT1 = `/bin/cat $archpath/$logfile |grep \"Ruleset based rejections\"\|awk \'{print $5}\'`; $blocked_spam=(split(/\s+/,$INPUT1))[4]; } # ..before we were using regular sendmail mailstats routine else { $INPUT1 = `/bin/cat $archpath/$logfile |grep \"esmtp\"`; $rej=(split(/\s+/,$INPUT1))[6]; $dis=(split(/\s+/,$INPUT1))[7]; $blocked_spam=$rej+$dis; } $table[$i]=$blocked_spam; $totalspam+=$blocked_spam; } # creating .PNG files ###################################### # # # Fancy drawing section # # # ###################################### # create the chart layout $output0 = "Blocked Spam at Inbound Mailrelay : $totalspam"; $scale=0.1; $im1 = new GD::Image(640,512) || die; $white = $im1 -> colorAllocate(255,255,255); $black = $im1 -> colorAllocate(0,0,0); $blue = $im1 -> colorAllocate(0,45,255); $red = $im1 -> colorAllocate(255,0,45); $im1 -> string(gdSmallFont,150,34,$title1,$black); $im1 -> string(gdSmallFont,150,60,$output1,$blue); $im1 -> string(gdSmallFont,150,75,$output0,$red); $im1 -> line(46,136,46,484,$black); $im1 -> line(46,484,606,484,$black); ######################## blocked spam monthly drawing ############################### # X-Axis for($i=1;$i<=$#table;$i++) { # autoscaling if(($table[$i] > 4499) || ($table[$i] > 449)) { $scale=0.06;} if(($table[$i] > 8999) || ($table[$i] > 899)) { $scale=0.04;} $inc=$table[$i]; $t=$i*17; $im1 -> line(36+$t,482,36+$t,484,$black); $days="$i"; $im1->string(gdSmallFont,((36+$t)-length($days*(gdSmallFont->width))),(496-(gdSmallFont->height)),$days,$black); $im1->filledRectangle((36+$t)-5,(484-(($table[$i])*$scale)),(36+$t),484,$blue); } # Y-axis description for($i=0;$i<10;$i++) { $im1 -> line(46,484-$i*30,48,484-$i*30,$black); $numb = (30*$i)/$scale; $snumb = "$numb"; $im1->string(gdSmallFont,(30-(length($snumb)*(gdSmallFont->width))/2),(484-($i*30)-(gdSmallFont->height)),$snumb,$black); } $xline = "[days]"; $im1 ->string(gdMediumBoldFont,(240-length($xline*(gdMediumBoldFont->width))/2),(510-(gdMediumBoldFont->height)),$xline,$black); $yline = "[blocked_SPAM/day]"; $im1 ->stringUp(gdSmallFont,(12-(gdSmallFont->height)),(256+(length($yline)*(gdSmallFont->width))/2),$yline,$black); $png_data = $im1 -> png; $chart1 = $destpath . &UnixDate($startdate,"%b%Y") . "spamtotal1.png"; open (PNG1, ">$chart1") || die "cannot create a file"; print PNG1 $png_data; close PNG1; &footer; close MAINFILE; $udate = &UnixDate($startdate,"%b%Y"); # send contents to the recipients $top = MIME::Entity->build ( Type => "multipart/mixed", From => "$sender", Reply-To=> "$reply-to", To => "$recipient", Cc => "$cc_recipient", Subject => "Mailrelay2 - Monthly Blocked SPAM Report - $udate", Data => "Mailrelay2 - Monthly Blocked SPAM Report - $udate\n"); $top -> attach(Path => "$chart1", Type => "image/png", Encoding=> "Base64"); open MAIL, "| /usr/lib/sendmail -t -i" or die "open: $!"; $top -> print(\*MAIL); close MAIL; exit(0); # these little subs can be useful if you need to create an html page within the script. sub footer{ print MAINFILE "
\n"; print MAINFILE "
\n"; print MAINFILE "
\n"; print MAINFILE "
\n"; print MAINFILE "
","\n"; print MAINFILE "

"; print MAINFILE "\© Seabury & Smith 2001 Dominik
\n"; print MAINFILE "[Return]","\n"; print MAINFILE "\n"; print MAINFILE "\n"; } sub html_header{ $document_title=$_[0]; #print "Content-type: text/html\n\n"; print MAINFILE "\n"; print MAINFILE "\n"; print MAINFILE "$document_title\n"; print MAINFILE "\n"; print MAINFILE "\n"; print MAINFILE "

$document_title

\n"; print MAINFILE "

\n"; } sma-1.4.orig/docs/0000755000175000017500000000000007642602725014231 5ustar apollockapollocksma-1.4.orig/docs/re_format.70000644000175000017500000002721007603333514016273 0ustar apollockapollock.\" $OpenBSD: re_format.7,v 1.9 2000/04/18 03:01:33 aaron Exp $ .\" .\" Copyright (c) 1997, Phillip F Knaack. All rights reserved. .\" .\" Copyright (c) 1992, 1993, 1994 Henry Spencer. .\" Copyright (c) 1992, 1993, 1994 .\" The Regents of the University of California. All rights reserved. .\" .\" This code is derived from software contributed to Berkeley by .\" Henry Spencer. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" 3. All advertising materials mentioning features or use of this software .\" must display the following acknowledgement: .\" This product includes software developed by the University of .\" California, Berkeley and its contributors. .\" 4. Neither the name of the University nor the names of its contributors .\" may be used to endorse or promote products derived from this software .\" without specific prior written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .\" @(#)re_format.7 8.3 (Berkeley) 3/20/94 .\" .Dd March 20, 1994 .Dt RE_FORMAT 7 .Os .Sh NAME .Nm re_format .Nd POSIX 1003.2 regular expressions .Sh DESCRIPTION Regular expressions (``RE''s), as defined in POSIX 1003.2, come in two forms: modern REs (roughly those of .Xr egrep 1 ; 1003.2 calls these ``extended'' REs) and obsolete REs (roughly those of .Xr ed 1 ; 1003.2 ``basic'' REs). Obsolete REs mostly exist for backward compatibility in some old programs; they will be discussed at the end. 1003.2 leaves some aspects of RE syntax and semantics open; `\(dg' marks decisions on these aspects that may not be fully portable to other 1003.2 implementations. .Pp A (modern) RE is one\(dg or more non-empty\(dg .Em branches , separated by `|'. It matches anything that matches one of the branches. .Pp A branch is one\(dg or more .Em pieces , concatenated. It matches a match for the first, followed by a match for the second, etc. .Pp A piece is an .Em atom possibly followed by a single\(dg `*', `+', `?', or .Em bound . An atom followed by `*' matches a sequence of 0 or more matches of the atom. An atom followed by `+' matches a sequence of 1 or more matches of the atom. An atom followed by `?' matches a sequence of 0 or 1 matches of the atom. .Pp A .Em bound is `{' followed by an unsigned decimal integer, possibly followed by `,' possibly followed by another unsigned decimal integer, always followed by `}'. The integers must lie between 0 and RE_DUP_MAX (255\(dg) inclusive, and if there are two of them, the first may not exceed the second. An atom followed by a bound containing one integer \fIi\fR and no comma matches a sequence of exactly \fIi\fR matches of the atom. An atom followed by a bound containing one integer \fIi\fR and a comma matches a sequence of \fIi\fR or more matches of the atom. An atom followed by a bound containing two integers \fIi\fR and \fIj\fR matches a sequence of \fIi\fR through \fIj\fR (inclusive) matches of the atom. .Pp An .Em atom is a regular expression enclosed in `()' (matching a match for the regular expression), an empty set of `()' (matching the null string)\(dg, a .Em "bracket expression" (see below), `.' (matching any single character), `^' (matching the null string at the beginning of a line), `$' (matching the null string at the end of a line), a `\e' followed by one of the characters `^.[$()|*+?{\e' (matching that character taken as an ordinary character), a `\e' followed by any other character\(dg (matching that character taken as an ordinary character, as if the `\e' had not been present\(dg), or a single character with no other significance (matching that character). A `{' followed by a character other than a digit is an ordinary character, not the beginning of a bound\(dg. It is illegal to end an RE with `\e'. .Pp A .Em "bracket expression" is a list of characters enclosed in `[]'. It normally matches any single character from the list (but see below). If the list begins with `^', it matches any single character (but see below) .Em not from the rest of the list. If two characters in the list are separated by `\-', this is shorthand for the full .Em range of characters between those two (inclusive) in the collating sequence, e.g., `[0-9]' in ASCII matches any decimal digit. It is illegal\(dg for two ranges to share an endpoint, e.g., `a-c-e'. Ranges are very collating-sequence-dependent, and portable programs should avoid relying on them. .Pp To include a literal `]' in the list, make it the first character (following a possible `^'). To include a literal `\-', make it the first or last character, or the second endpoint of a range. To use a literal `\-' as the first endpoint of a range, enclose it in `[.' and `.]' to make it a collating element (see below). With the exception of these and some combinations using `[' (see next paragraphs), all other special characters, including `\e', lose their special significance within a bracket expression. .Pp Within a bracket expression, a collating element (a character, a multi-character sequence that collates as if it were a single character, or a collating-sequence name for either) enclosed in `[.' and `.]' stands for the sequence of characters of that collating element. The sequence is a single element of the bracket expression's list. A bracket expression containing a multi-character collating element can thus match more than one character, e.g., if the collating sequence includes a `ch' collating element, then the RE `[[.ch.]]*c' matches the first five characters of `chchcc'. .Pp Within a bracket expression, a collating element enclosed in `[=' and `=]' is an equivalence class, standing for the sequences of characters of all collating elements equivalent to that one, including itself. (If there are no other equivalent collating elements, the treatment is as if the enclosing delimiters were `[.' and `.]'.) For example, if o and \o'o^' are the members of an equivalence class, then `[[=o=]]', `[[=\o'o^'=]]', and `[o\o'o^']' are all synonymous. An equivalence class may not\(dg be an endpoint of a range. .Pp Within a bracket expression, the name of a .Em "character class" enclosed in `[:' and `:]' stands for the list of all characters belonging to that class. Standard character class names are: .Pp .Bl -item -compact -offset indent .It alnum digit punct .It alpha graph space .It blank lower upper .It cntrl print xdigit .El .Pp These stand for the character classes defined in .Xr ctype 3 . A locale may provide others. A character class may not be used as an endpoint of a range. .Pp There are two special cases\(dg of bracket expressions: the bracket expressions `[[:<:]]' and `[[:>:]]' match the null string at the beginning and end of a word respectively. A word is defined as a sequence of word characters which is neither preceded nor followed by word characters. A word character is an .Em alnum character (as defined by .Xr ctype 3 ) or an underscore. This is an extension, compatible with but not specified by POSIX 1003.2, and should be used with caution in software intended to be portable to other systems. .Pp In the event that an RE could match more than one substring of a given string, the RE matches the one starting earliest in the string. If the RE could match more than one substring starting at that point, it matches the longest. Subexpressions also match the longest possible substrings, subject to the constraint that the whole match be as long as possible, with subexpressions starting earlier in the RE taking priority over ones starting later. Note that higher-level subexpressions thus take priority over their lower-level component subexpressions. .Pp Match lengths are measured in characters, not collating elements. A null string is considered longer than no match at all. For example, `bb*' matches the three middle characters of `abbbc', `(wee|week)(knights|nights)' matches all ten characters of `weeknights', when `(.*).*' is matched against `abc' the parenthesized subexpression matches all three characters, and when `(a*)*' is matched against `bc' both the whole RE and the parenthesized subexpression match the null string. .Pp If case-independent matching is specified, the effect is much as if all case distinctions had vanished from the alphabet. When an alphabetic that exists in multiple cases appears as an ordinary character outside a bracket expression, it is effectively transformed into a bracket expression containing both cases, e.g., `x' becomes `[xX]'. When it appears inside a bracket expression, all case counterparts of it are added to the bracket expression, so that (e.g.) `[x]' becomes `[xX]' and `[^x]' becomes `[^xX]'. .Pp No particular limit is imposed on the length of REs\(dg. Programs intended to be portable should not employ REs longer than 256 bytes, as an implementation can refuse to accept such REs and remain POSIX-compliant. .Pp Obsolete (``basic'') regular expressions differ in several respects. `|', `+', and `?' are ordinary characters and there is no equivalent for their functionality. The delimiters for bounds are `\e{' and `\e}', with `{' and `}' by themselves ordinary characters. The parentheses for nested subexpressions are `\e(' and `\e)', with `(' and `)' by themselves ordinary characters. `^' is an ordinary character except at the beginning of the RE or\(dg the beginning of a parenthesized subexpression, `$' is an ordinary character except at the end of the RE or\(dg the end of a parenthesized subexpression, and `*' is an ordinary character if it appears at the beginning of the RE or the beginning of a parenthesized subexpression (after a possible leading `^'). Finally, there is one new type of atom, a .Em "back reference" : `\e' followed by a non-zero decimal digit .Em d matches the same sequence of characters matched by the .Em d Ns th parenthesized subexpression (numbering subexpressions by the positions of their opening parentheses, left to right), so that (e.g.) `\e([bc]\e)\e1' matches `bb' or `cc' but not `bc'. .Sh SEE ALSO .Xr regex 3 .Pp POSIX 1003.2, section 2.8 (Regular Expression Notation). .Sh BUGS Having two kinds of REs is a botch. .Pp The current 1003.2 spec says that `)' is an ordinary character in the absence of an unmatched `('; this was an unintentional result of a wording error, and change is likely. Avoid relying on it. .Pp Back references are a dreadful botch, posing major problems for efficient implementations. They are also somewhat vaguely defined (does `a\e(\e(b\e)*\e2\e)*d' match `abbbd'?). Avoid using them. .Pp 1003.2's specification of case-independent matching is vague. The ``one case implies all cases'' definition given above is current consensus among implementors as to the right interpretation. .Pp The syntax for word boundaries is incredibly ugly. sma-1.4.orig/docs/re_format.pdf0000644000175000017500000002643607603333514016707 0ustar apollockapollock%PDF-1.2 %Çì¢ 4 0 obj <> stream xœZ]sÜ6²}ׯÀÃVµ™AüÀÍCJ»Ñ­òƒ7YY·v«¢$¢f(‰1‡œœÈªÝ}ÖKþÊþÇÛ  AÙ®TlKtãôéÓ F\°ÿso÷g¿ýÆ„ùýµÝ³¿\Ÿ}}•â/®ïÏÛ˜§,‹Y¦»Þ¿¹ºüå¿¿zwq~ýë™àiš²ë홈"®¢„]?%1%¼s½{s}ó&»9gïqh„Ã" ¤âIšØ!ÏýPîÙUy_ve³-Ù»¢95¾G)£Ì;¹èb%|úõUæö¾‰xŒÃ6J%00f›ÔŒýÛ…ßPRî¬ùïãÔ’»½ÿþí?á…HÂvº¤’+¥µ}üp¬‹Ž™ßÇ—’~ÿñЕ}_µM?3KèˆÃ  ì†}wùþ¯Wo¸~ûýߦ›“íþÊLñD(ãx==µvžÈÅÚìæÍ­³ ŽVp‘ÈÜŽ¹½º\ápsbÜ r²xÕ'«J|7…SÓÚùéæ|ÍŠžíÊ?šrǪ†ý8iͶí¾ÄßO8äNAèÉÀ±ÂZ{¿\H.•ƒœYÿ?lßîÊ®aW—hM×ëg6<¶}é-ÛH°ÔŠ\f'þúJDÁãÌ™W>tåaæló2L$#gáqsþ³Èº_©Ì81âY9Go‹ºîa/e_²ÑÏ pz?›]f<Z» |ÊfWîŒûc®UŽˆeÏê*pŒÂà;Ô<¿ì!.‹fÇÚ»¾­Ë¡<å¶ð‚=â.w*wKG¤vµWxÉ”?Nã ‚Ýí­ßuÂõhï]±1oª9ÖtH}µ]Y€¨xrùö!²þÃÏÙ÷Îr{8Ú Ja7BçÄ9=@§ÀfP’ð(öÑYõN`wÅöƒi’ƒ{éqÑíŇb¨îªºžÎ=º­wìе]±ï¿Á“-°þÍÍv,=>çh÷Ä”z’¨êšÝ•lWõK±J-žuÎeæ]µ=ö=DZ1àŠ ÐÃq8,”Ää|ÇPuY¸S‰ß’Šy%nàïnË™2,¬ šöÓ‘{É\@&±ƒ z èåvè]:Ö?7CñÑ`±/÷E3T[xt(›oØíËŠí‹îŶ²tÔ6cÌ ¥x¤å^-9ÜVU¹;ϯ+°Ý;oë×wÐy™JÈym³ß5è?ÎÞÖw22ÀOˆ[Ó{Î:Çp:à®ÖðS]·æ|¥æQæ¢ÿÉÊì•À«‰J<–Û¶Ù­Y9l;³¹;;cçN°—܉~AoÚãûPeqF 7´û©ýŒqȇ„Ä„ž71Q<Í“|fbà©á oÝÊq¸2ĆP”ÿüʲîDVkvûþñ-üÑv§ I >ršî®=6»9œãb7'¿ Z¥_;—5ÅÄ¥‰Ë´B¹WÁM£é2å:RzbúIƒey”@øçåî¬îtïOì@ò\(TyÓ rç©ÁóÛÑ(pÌÈs¡ÖE+ºjМ¨é¢1õCN”‰˜ÙûÕj¤.+¶Esy„¿¶Öñy{± ©<ѳ]|ûÚ.ŒñâUËMÖh¢ˆšá ˜U$^·,¡ñÈê#ÐÛ Épˆ¸Û­Æ + }æ¶¢aǦ¯P0c:Ü5hŠaô•‚äÏCÙY¼â ¯Ò=Z‡ à¶"ì¿,ŸÍ£ É’™óÖ“é-bÚ¹ã­ÕéE<Í,ÁQ·§V+ ƒ?nì°,Š-ó¡tÑ^Þ@ÿ´s´†’)™ºÒ~“{RÏø^þغ"™N¢~ cÝm%(!Ÿû Òa€œ#ÿ?6¹BÝšÅdäõcé·*%O#z v úó2³® O–ÃSY6ð•”Ãßýß¿¼»ø§uK*lLÇÀl9$ç–›7q’¼€©šm}ì«¥°ƒÒUè¹°"vYègº[q“ Bg"H£€ÿ©tssY‡73¢ÝÖ¥;3Âüæ~˜,‘Ø\Ç>×>–ûµÏ™^Û™Mk¬˜¨¸ù¸-Áá8ÐfDãô *¨„qIr=ËI™‚øv•zßšØбjPø ¨™dÂòœÃ\À c Š"¿` a Ô^JÅž|Ób]±/^!¯`õ¥U+ÅʘÙbˆX ‰O¯ŸM%Ì)öÍ©8v®)\¡¾Ncò[ó‰´0ʃ‚Æë/ð¯^'J9é_l§ÍK¤íU¶V£{‹Oy÷¤lO€u“äóË(Zætj%BUNØ$kÆÓì¢!ªT®&SQ¨Æ&ù#–ò³µ1êV¥â3œ¨­Æb¤_æ pg¬„ÚϽ‘ëÛI3¿$8uAr|bQº§¿.³§óh0Å–[SŠòOmjx4Ù@Ï™Wo¿žzZ†o]ÏûQ2èYLH8å]hÕß  ö½95žÀ$¡§Òn!Rbm©”¹žX¹e¯+y啼Žú@ 66º^Ë4 /Ol3Ñ&ºh£‘Öâù‰¥±é~Æ9ÎîØ—(|ñ!4=zBÝZ9bßun—ZMún í?1žbC¶s§RI#Ÿû“SE‚˜m‹²UÙ™ þ¼r'™¹¶VÕr8¯µºî,WÉÊJUcÊ=@¯®šÒ¬ô§O¡!hœM_+I7« %åZ&;*ÌN$» â­‡Šàgþ㟦ÿ>U bBÚë3ñWßþ ö8µìñK±¡ø`!- R³À>C»ª)ºçéÁÌí– ud,OÚ­_Mò UÕz„ À/¥¬öÜN*[í “Q÷Ü4ðü¾^¾ÀÄ,á‘ú¼‰Ë}‰+MC1 àV9…¶åu`ÝÌãl¢gãÈôÓ"õ¬ñ"{,P×QïH9 C¶É|y~‡âÙ®l†< Kjšv>UÃ#jDÛÛÄŠ¨úc[`F|Õ77çÔ{Sc] Ó„+*ç.nC¤¢ƒÔ”ðÂÚ2O*¦-G r$…9WÚ‹Âbrƒ¹Áñ¿·ÏÚÀÙ±]õP ¶]õÊâªcc=FANWCëf²dì šÔmmH 2቗31ªêŸ{"I66KagU]—.DwEP=“„Ævz=Øô’jáåcybß ¨gˆ"6è‘+Èô*ÎýUॅâÎ6z_kd€/òU˜åHx|>ËI› >‘åü=]ä|£ætšË}š“>ÍaRã… œHÀ ÙñãOÔÙÎc{ š`<ñ§Õà/ÞL{ÜhÇ(5Tû µt'f…äH·“óà¼ï\]§ï„IVªƒ kÇÍÓ÷†d¢ýýÌq`“lÎ…J…<•cZçìíýdðÕˆ]¿„ŵ\æ®{ŸWkVÍÛýnIbD8@ºQ›æöŒ@¥ñiO8û2¨5ÅÁ̾è”msŒEƯŽAƒo@“ÛÀèú\»r^ [&®v(£/ڔ¹s#Šî{ßáø˜|¢aIÒËmHjnpJ.iÀˆT¼ë¦ƒÁîI?¹“ùï ÛÈ&=ëÛéoçå2^lÍü2íñÄPŸk*Ï»±©¢ˆŠº›¿tEt/4ugfvN<‚˜MV YÄqƒÔ·²ʾ+œØ@£žP 7¡lR¾)wªÛÚiÖºR‹+É›óŠV»‡JkIµì„M5u* T(É ³ò=U—kVòšñÇh£Záé]¼ÿëÛ·Ëp‘£€ˆ! cå® Ÿwa9'áå¶r׸i;ÇJEzì×6ëh*ü¦B~I¾8‘Ó|cצulÒqP¨_,¶ÌY)P=cÌË W$|wˉðfÄ;¯hÀC  EPc}ÖìmÕ ÞƒÅf»)-1ã6ñg)” „Wv|ÿwS¬(`Zjª•˜ïéx6}¹ )pK4Ê'{p›]yÀ/'pBþ6˜.ä1¼ŽõŽQØXGqnq6*RÈœ;`ŽúÙö¨0$] Aï|£ms?AP”o¯[VØsâj17+"~WšÄç~k‘F<±´} þÍMRq’·N‘æÑ˜}‡ÅŠ jÇh ÖjHÔ^Øi8y²…»»Ü+1a897;OøØÇxÕ茢ui6°_p¬)~ûăs¶ÝúŒÓg'Öz¬¤å Û•°¶#ÃÄSÛùuú \Àj¨!ƾxëÖQ¾'Ó-WÒ eu ûm_Ú‡ƒU’B}âCTÀ6ª€^ïÂãb~Èe±çÂ~æ>¬r|ל–´ô¤¹…¦4HÜvÖ$¢P 後ˆÒ<¨€H÷®Â‹7?¸Ç_·‚Ù·  ´àNo:~L§=!Ò)Æ9ՄäVHR›V3žùk Ï×¥ý¢ƒÍÚ °\Fýy «@8ýƒ¼’¹ºÔ÷ÇA™€™oŽü§rÛò€ŸŒ8áà¾)¾ue\š‡Wôæ3üfÛîï `1›°#ÖqàÛ•Ûjã'±µVšŒ—­†ÚèêðØ›R¼®©Ü;@3ÓïÚÞüìÌô ù×Ìœ%Œ®º1¨h~jQºiÂêUa…5×Ì캙ÇdénaðK˜hñý"AÚ¤æ 6ÌÓ”Xð!X- DÖ^­NU_ Œ«R^õk®M' „b×ø¥Çøi!~+G%~x«Ž S@r/þõPmF¢ôg[\›¥1oõx-V¹pÓ©°á–"…øöþ“¹4[ó¬* ˜GAžŽç̃³:m††[ $©kÚ1Wºí6€Ó}Y!†nÎgU_î"ލÜäD¸Ó’xý@=Š÷~ì÷^µR²æ*Ï]63"b’°g 1ïÞàd9Íe[CŒçÄ—f17©Ÿ ã‡HرÝIÆ"wÕ«t:‡·é‚)¨d<0{ ­TI«á '‹È—ল`~VàvˆsM•¶Û¶€¥kÁ ±¼Hâù>›‚ígø\6~ì]÷ÝÜI™Æ ¶#ñE¿Cä°”bÝÝj€Méøñȯö“|,¹.' ¡ËcE×sF V®ºÛŽÃÌÏíöqµ´ÅÜ [itu  ý‘oùO?¹ªhúa –”T -§:M‚ÆévüDdòÙ6¯$èŠ2ö—÷߱ˇ²«Ì÷ƒîãõ˜;añ®èÀ½q´f@kÊ> >> /Contents 4 0 R >> endobj 14 0 obj <> stream xœZ[oÛF~÷¯˜‡äìZ,gx6»h±)Їô’h(YSÔÈbC‘*I%v·}îKô~gn$Eº-ŒÄ²8—3çòïqæÓù]¯~ºú‰qõýUÙ·WŸ½Žé‹Ûýgkõ”%‚%aÈnׯ_þ÷Ëo^¿úüÙíWÜ‹ã˜ÝWÜ÷½ÐØí§«Hx"ÀœÛÝõíæ:ÙëGx&Ø:Léñïm׳ß?ªe½ˆFˆÔ ã,Ó³eáfrî©þö·yÑ˶cÍžÝü+F®qXµMyiˆUÖ\mó}9œÔK¹:,Ç»O(k–³-Öý@#ÃÔK„¢gR/Íx8µ²ëʦ¾Á¼¢©ª¼/ë{&+y”5&ÔEÕtrǰîÝÛ+–×;v÷âÝŠ•>3ùÓ¹4‹È@Ä;5;|Ìg2gO³,ÔÏ+e–¢Ê»î†u=6€jІjø:ˆB|&-š±oZÖ$ë°;MVú+&ÚÌ«j~šî)qÃÈ‹²tA\rȹ¸=ë÷¬©å TSTgš•}'«½² "›)›ë¯ö$p+YÞJ}´H˜£¥™—‰Ô­nXC#Ÿ4 àØ|I±‘ƒ¨ÙHÔ¹n”òúVæ½²1Y²c¥Ñœ†ïdUK¥ÐO$úÝ[u°Àói+#PÀ/LŒ¬â¾—dVbòïÝÊÓ„£ñáhA쥱Œ/›!^`îsý};™·èq­òäÃhž%Z!bPH~Ÿ,›x |{ ¨…”v”Ç­u¼§b‚û»dÁrfݧc;Pð½}Ѽx÷nu£?j/JƒÑp[É_,íúafl¥VRÁü¶YX,$Œˆ5Þ¿Ó¸g /ÌÂ,Y°¹ULGƒŠ(»ÇzmF’×g‰óØ®©p*1-t›sç±Ïk7x\±xv©g{Ù\×!aËŽù#«›þ7¶•ÊlõîÔ”ˆ²"kóú^N±8…N²'°8áÑ_ã(XãD„s0&·ªó£TÒÐÀÏ^snræ4p¸ŽŒÊŠÃèÜäùFy«mläDZ†¨ ÔÔ:ÑÙÜLÕACR¬“|’ž›”ð)AwÇ,ëB}KVTÀ¿Æ##h^9»oóÓa6±;å…4åÓ‰Û*¯?°JÅDÉÔs(!ryèÊΧ“T&­à ¸ÖvŒÕTÝ·;µðЙÃà BŸÛöзÙImgœ åAq;ù{­¬j¼Í·^ œ, ½Œ['ëOrê*0ª¯Tø6ç›gˆÝ‰P>ª¦È+©¢ðÔ6vœÊбŽdsÁÇr'uRìl¢Q6# /‰¹úy1 I³÷³)ã¼ÝàQÕ]6È@Àp&OÏ»?l¥£Ê)\çzÖ2"6â^èèFÓEv(’ùF×'Y”9¸LýF;;8qã0ÁI4‡“î¹²ù05ò'JÛÇFc‘ ¶a J;Ïÿùyä·Ïÿ¥þ:æ}q õõ" Ì*Îã÷ÖgÊ}KáÈVÒ¨ I‚°(…è¯Õl )?“¢•3Adu†à‡XPMoÀH½V¾csr«Gú>RÒRFCÊ·S¼Ïíš*§ Q9èûÔŒŒ¥ÊæšL·#*eˆ\ÆT:ˆ:§ª@ §ÐQ¸6l7ŠMrD&äNušJ(ËײTüv)äÕè=8ž˜ÙV4¸²cÛG½1êˆØÑ°f ž:¨ Þ(“ $6¨> q¤À ZY¼´œ® .–+XÚOl>"¾Ì6fq‘]|XxswFQ±0Q{IèÖh~û¸` øAd`¡6èÀP[6­ÝTÁI€’зëÎõ:,šVc4'«çÛ”aê$EÏ­ZzYëT_4Çú`ø Æe[J°‘%kç^Áy|ù»¶ê·ß¼ùꇀ1YU Z<¡ ^whÎÕÎa™Ú¢ÈÏ=ö¦Þ5{ RDÞ WxñȽ‹1óÔ´}Nö¶>éT]ÝDd餓Å¿ªu=±Àôî<Éfê–™pvª¶ˆ @‰¯_BWt 9ÇFÑo<@ƺóÖà‹Bûd([ðë‘=²ì–cL™dˆÕ&š A % ²'ý©Äèó¶7-É’gš:ã¨Z,o«R‚•ZMZt«Í$¶Ä.°@¬+È¿ª%…ÃZü§*Ÿ~,°NMBX ·3Rƒ€{sÞhOôÈëŠÐQ‚È«®²3 `k<'ßqâQÞþøÖTlóû6/­±é»O‡¦²9%ÑŲÝÙ¥iÚ‹Ø{§v£ßv·íè^hàŠR…t—²;…iôÖ.ÐwŸ `^M[öºh¼p,kfŽ•Ì«äÄ8–©mk9ˆ1®”@F3W)¡”×<1ò²Ìä'á*ïëÑú™vÜÈK|û¼é¥Ö?èu4#ÉH|3h]Mc–ø³;ÁGã4aÆç9uÌá±%]ÎYf™˜{O8w¤ëÉú.qd–âÉÓäˆÜäà,°‚§­À¿Cÿ/¤íç{ ú~f‚ñ ËÖPzmÿØ‹ ó¶°{Z£ÁHaùq±pRDf‘6õçä*w©œ,J¿ Ö! (®RºÁ› L'ôõ•Š+”Ê÷ýATì(óîÜêšo`7*+ÍL†Q¤´ì¨#˜„ÆF® /†Íá§¾EØWDö$l@ @»+Hi5àÕJýpÜÔ€,•çþ6PÞ¨*oî )\Fø“n¼ÈO×r²Ý‹4[qÅ·üäÁô”î¶[C;ĘvD ˜¶û÷)å64nµ:N6Ku΢®ŠåC®é­„]ÊÝ®’½Ï»|»Ý«u(ÛܤfTÄ™#Kw8ªüÿ>€æ\¨}÷‹þµy¶ry‚š7à—{ÐD=x¨UªÍµ·¤‚ H”æ–T`ŽJñbfä¥#¿˜z<äcµ•¦¶‘õûnÐ$iÀ8XêBG $}Z"È®"G"êL9-2SÃê|p/è¸X)Cœ5>tåÏXq”ot¥Ïçp7Õ®2å8¬ˆ¶YæK:ÔI°%âS:½˜HÙ=³ŒòbÑ t¦Ò”»e…#•‡ A‹“%) ,«R¬†¼úXÅun· •CÒ§¬K*xZ½Á…‹JÕ³B¦œjmfZ’ºW•õº×=á­ A2Øc·¦{r¯y2Nm[!{"1x<Ú¨.ººzÀ¢lWv€Å¢WéíïØG+Š®òròÀVeGÚÛ·ÍÑR3ÅÜ$þ¸–V­¨­5û>bÖÔ}“Ôã®XFÚ‘e¡Ó¾«¸]ñÿ;Bõã¹êËa uX~: u¦ó ¯¬óöqTæ5çžPyÜßÔž ýº:Köä]‡ þI’-ôëÁ‚Â9÷Ú¡¥Ò²6€NsH¹Â&Œý¬Zñl^c,ïS=2°ÏºÛ7íQ%9ÐÒÑÁ¨Kýø¢Ó‚•læâÑ%Ÿ¡¬ÕÃïÉ”s+µÞ0éÝ{H+ÐVÔ}²ÓùŸsÝ6Ô!Ë\Xܽ}øáÝjlçXŒñ)²›B7Ö\e}i”,ó|ΓY—h¨CG€ÖsQb þk{½B{ÚZ;SNšI$T¦¯Ñ`Ýð¢©d`"ö:ðÁÐÀC{ÒAˆÎ47פ+àPÂ;§.¦UbZPï§OÞ+m™t/Áqš¯‚D¹ÊÁÝèf‹<ª‡¢ª¸Ñt_s:òë—ÝošÇ 'VøoÛæ¾ÍÝ“õ±)¶‰IƒEôáq6ý<Ú†0^°‘ÌQ3l=a:"ŠQñ÷ä>:K¢Ä´rUÄøª•{T÷$M^òDœ€D+‘¦Zy„/êžÁšÚ U9\ÆøWêÞ‚eL”÷Ͷ,£xØ\ß¹yaH¥£9ÑÝ6ïJƒïv:Xñp¾‚%5™Bhúw¯Ì¡á.!~2/ v¥ŠúhðªBë–º ‚.Ÿæí?'Ö´"Ë+ÛJt½ m••±[çîºwû‡½2û÷JÅÕºqCÓÉkæ©Î0õñš'î cAWÝKW¼ãËèñ ¯ié£$ÙŸuºÉ+”@ºJ ÃÉ ¤0HàÝÎF”ú®¾ßþÒú[ ÂN×w›ÍÿLn6¿®L¡}g¿ûue:p¾É·¥›Ñù¬L&Œ}gÑ›3º%½*Ûd¨uc‹e·cr µ”(¡û ‹ݤ ¨·Ï;ú8›kw0_{ áÛgƯsg/âÀ‹üÄ‘—G6>½s‘ú~ZOßÙÓk(Ö³ïÞÛW+’®¹dB©d/~T¬OêQꥑõ[ÛPo\÷¨i3ƒM“ÊÏL3•ÓDg¨ÑÌü)†O£y¹ûÛŸvå®/Æ´ÿ/¤–.º¸¹fH‰Ö;©ÿ@Z°¶8N’™x‰cÇ y"Z.Ý€×<˜ñåŒ^°H®må‰ÐP¼zÜü1òSç½m0WV©S¯åbc3Ó¦®‰Ý…ù’¹M Z_ô& á(Ízê *ÿã«Ó^ÒÔ+{’<Ú~•ÌÕË1ðlSçi4B%‘‰É/qòJßÉ€ é×1bw×3nÉÄЗØ!wMk‹«Ô­åd!ß6-}묟†Õ¸¦ÓòÉ^„&1 õ¾ÍØ»úæx3»·ù0po=lóBËàk¨çe¨Ñ‡vØ\5v,TìG7À£ËöÙE…(×C¼Žâ>¿é' L¢ã°¨9Ûf³®‰ Ú$µÆ6×D9RR½þY¶ °¿(HŒîVùò¨ô‚»ŸÝMåsÛ§*ÍóŒÛä½Ö0¾Ý‚q/ ldƒtgáäìhjL¸K’¥15‹—%sk›hÈ/ûv $ôgÀß®Ïôžj°Û0@„ûÁ<³h )J]ÿé,‡žëÙ¼?°o~ñæ?ìåà Ë+fgÞPž±ß«¼¡þ ƒÍCõE€‘QÐß/oÙwWß]ý—b6endstream endobj 15 0 obj 3943 endobj 13 0 obj << /Type /Page /MediaBox [0 0 612 792] /Parent 2 0 R /Resources << /ProcSet [/PDF /Text] /Font << /R12 12 0 R /R11 11 0 R /R10 10 0 R /R6 6 0 R >> >> /Contents 14 0 R >> endobj 17 0 obj <> stream xœmVÛnã6}÷WÌ›"æŠuCŠ,š^€fÓu\ @U4”D;Ú•%¯(Åñ?ä£;CR¶ÓAà„œû9sè€qèÇ–»Ù·Ù7àölú(wðq=û°Šé`½™qXÚ[H$RÂz·XÝþóÓýêîæjýeÆYǰ.g<˜ "Xf‘`"DŸuµXç‹$¿‚2 È, JÅ‘39šAï`¥7º×m©áNµ£jÈA1AâÌÞMú¿L§1ìññM=6PÄ2á×µÕ¶ËÀšÈÝ4öÀÌ/ROc R|3¼ç¼:SŽ#G'EjÔÔ›-K¢2ĸ¦žfÛÚËí ',ÙiWõ…\d8γ,¨ËL™§|ѽ‰…“¡36Íç{ºˆè ç~â”)Ïa‘öb:÷R\âêÖŒ8’]GhL+Úõxdè¹&ÙµO6<öøX¹ýu´‰ñ= ²ôRæÍ7üÅŠ‚Î8aÙIQ9QKƶR=è×mÙëª.pãÆ­“>¢ìùmòìv¸”xJZõð#=›º¯­šø¯/øíĹܩ×E×À³LºåÆÞÝeHÿß®áóìóì_È@Žendstream endobj 18 0 obj 1210 endobj 16 0 obj << /Type /Page /MediaBox [0 0 612 792] /Parent 2 0 R /Resources << /ProcSet [/PDF /Text] /Font << /R12 12 0 R /R10 10 0 R /R7 7 0 R /R6 6 0 R >> >> /Contents 17 0 R >> endobj 12 0 obj <> endobj 11 0 obj <> endobj 10 0 obj <> endobj 8 0 obj <> endobj 7 0 obj <> endobj 6 0 obj <> endobj 9 0 obj <> endobj 2 0 obj << /Type /Pages /Kids [ 3 0 R 13 0 R 16 0 R ] /Count 3 >> endobj 1 0 obj << /Type /Catalog /Pages 2 0 R >> endobj 19 0 obj << /CreationDate (D:20011113122642) /Producer (GNU Ghostscript 5.50) >> endobj xref 0 20 0000000000 65535 f 0000010933 00000 n 0000010860 00000 n 0000004406 00000 n 0000000015 00000 n 0000004386 00000 n 0000010682 00000 n 0000010610 00000 n 0000010536 00000 n 0000010770 00000 n 0000010465 00000 n 0000010389 00000 n 0000010319 00000 n 0000008646 00000 n 0000004610 00000 n 0000008625 00000 n 0000010135 00000 n 0000008832 00000 n 0000010114 00000 n 0000010982 00000 n trailer << /Size 20 /Root 1 0 R /Info 19 0 R >> startxref 11070 %%EOF sma-1.4.orig/docs/re_format.ps0000644000175000017500000005562307603333514016560 0ustar apollockapollock%!PS-Adobe-3.0 %%Creator: groff version 1.16.1 %%CreationDate: Tue Nov 13 12:26:30 2001 %%DocumentNeededResources: font Times-Roman %%+ font Times-Bold %%+ font Courier-Bold %%+ font Courier %%+ font Times-Italic %%+ font Symbol %%DocumentSuppliedResources: procset grops 1.16 1 %%Pages: 3 %%PageOrder: Ascend %%Orientation: Portrait %%EndComments %%BeginProlog %%BeginResource: procset grops 1.16 1 /setpacking where{ pop currentpacking true setpacking }if /grops 120 dict dup begin /SC 32 def /A/show load def /B{0 SC 3 -1 roll widthshow}bind def /C{0 exch ashow}bind def /D{0 exch 0 SC 5 2 roll awidthshow}bind def /E{0 rmoveto show}bind def /F{0 rmoveto 0 SC 3 -1 roll widthshow}bind def /G{0 rmoveto 0 exch ashow}bind def /H{0 rmoveto 0 exch 0 SC 5 2 roll awidthshow}bind def /I{0 exch rmoveto show}bind def /J{0 exch rmoveto 0 SC 3 -1 roll widthshow}bind def /K{0 exch rmoveto 0 exch ashow}bind def /L{0 exch rmoveto 0 exch 0 SC 5 2 roll awidthshow}bind def /M{rmoveto show}bind def /N{rmoveto 0 SC 3 -1 roll widthshow}bind def /O{rmoveto 0 exch ashow}bind def /P{rmoveto 0 exch 0 SC 5 2 roll awidthshow}bind def /Q{moveto show}bind def /R{moveto 0 SC 3 -1 roll widthshow}bind def /S{moveto 0 exch ashow}bind def /T{moveto 0 exch 0 SC 5 2 roll awidthshow}bind def /SF{ findfont exch [exch dup 0 exch 0 exch neg 0 0]makefont dup setfont [exch/setfont cvx]cvx bind def }bind def /MF{ findfont [5 2 roll 0 3 1 roll neg 0 0]makefont dup setfont [exch/setfont cvx]cvx bind def }bind def /level0 0 def /RES 0 def /PL 0 def /LS 0 def /MANUAL{ statusdict begin/manualfeed true store end }bind def /PLG{ gsave newpath clippath pathbbox grestore exch pop add exch pop }bind def /BP{ /level0 save def 1 setlinecap 1 setlinejoin 72 RES div dup scale LS{ 90 rotate }{ 0 PL translate }ifelse 1 -1 scale }bind def /EP{ level0 restore showpage }bind def /DA{ newpath arcn stroke }bind def /SN{ transform .25 sub exch .25 sub exch round .25 add exch round .25 add exch itransform }bind def /DL{ SN moveto SN lineto stroke }bind def /DC{ newpath 0 360 arc closepath }bind def /TM matrix def /DE{ TM currentmatrix pop translate scale newpath 0 0 .5 0 360 arc closepath TM setmatrix }bind def /RC/rcurveto load def /RL/rlineto load def /ST/stroke load def /MT/moveto load def /CL/closepath load def /FL{ currentgray exch setgray fill setgray }bind def /BL/fill load def /LW/setlinewidth load def /RE{ findfont dup maxlength 1 index/FontName known not{1 add}if dict begin { 1 index/FID ne{def}{pop pop}ifelse }forall /Encoding exch def dup/FontName exch def currentdict end definefont pop }bind def /DEFS 0 def /EBEGIN{ moveto DEFS begin }bind def /EEND/end load def /CNT 0 def /level1 0 def /PBEGIN{ /level1 save def translate div 3 1 roll div exch scale neg exch neg exch translate 0 setgray 0 setlinecap 1 setlinewidth 0 setlinejoin 10 setmiterlimit []0 setdash /setstrokeadjust where{ pop false setstrokeadjust }if /setoverprint where{ pop false setoverprint }if newpath /CNT countdictstack def userdict begin /showpage{}def }bind def /PEND{ clear countdictstack CNT sub{end}repeat level1 restore }bind def end def /setpacking where{ pop setpacking }if %%EndResource %%IncludeResource: font Times-Roman %%IncludeResource: font Times-Bold %%IncludeResource: font Courier-Bold %%IncludeResource: font Courier %%IncludeResource: font Times-Italic %%IncludeResource: font Symbol grops begin/DEFS 1 dict def DEFS begin/u{.001 mul}bind def end/RES 72 def/PL 792 def/LS false def/ENC0[/asciicircum/asciitilde/Scaron/Zcaron /scaron/zcaron/Ydieresis/trademark/quotesingle/.notdef/.notdef/.notdef /.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef /.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef /.notdef/.notdef/space/exclam/quotedbl/numbersign/dollar/percent /ampersand/quoteright/parenleft/parenright/asterisk/plus/comma/hyphen /period/slash/zero/one/two/three/four/five/six/seven/eight/nine/colon /semicolon/less/equal/greater/question/at/A/B/C/D/E/F/G/H/I/J/K/L/M/N/O /P/Q/R/S/T/U/V/W/X/Y/Z/bracketleft/backslash/bracketright/circumflex /underscore/quoteleft/a/b/c/d/e/f/g/h/i/j/k/l/m/n/o/p/q/r/s/t/u/v/w/x/y /z/braceleft/bar/braceright/tilde/.notdef/quotesinglbase/guillemotleft /guillemotright/bullet/florin/fraction/perthousand/dagger/daggerdbl /endash/emdash/ff/fi/fl/ffi/ffl/dotlessi/dotlessj/grave/hungarumlaut /dotaccent/breve/caron/ring/ogonek/quotedblleft/quotedblright/oe/lslash /quotedblbase/OE/Lslash/.notdef/exclamdown/cent/sterling/currency/yen /brokenbar/section/dieresis/copyright/ordfeminine/guilsinglleft /logicalnot/minus/registered/macron/degree/plusminus/twosuperior /threesuperior/acute/mu/paragraph/periodcentered/cedilla/onesuperior /ordmasculine/guilsinglright/onequarter/onehalf/threequarters /questiondown/Agrave/Aacute/Acircumflex/Atilde/Adieresis/Aring/AE /Ccedilla/Egrave/Eacute/Ecircumflex/Edieresis/Igrave/Iacute/Icircumflex /Idieresis/Eth/Ntilde/Ograve/Oacute/Ocircumflex/Otilde/Odieresis /multiply/Oslash/Ugrave/Uacute/Ucircumflex/Udieresis/Yacute/Thorn /germandbls/agrave/aacute/acircumflex/atilde/adieresis/aring/ae/ccedilla /egrave/eacute/ecircumflex/edieresis/igrave/iacute/icircumflex/idieresis /eth/ntilde/ograve/oacute/ocircumflex/otilde/odieresis/divide/oslash /ugrave/uacute/ucircumflex/udieresis/yacute/thorn/ydieresis]def /Times-Italic@0 ENC0/Times-Italic RE/Courier@0 ENC0/Courier RE /Courier-Bold@0 ENC0/Courier-Bold RE/Times-Bold@0 ENC0/Times-Bold RE /Times-Roman@0 ENC0/Times-Roman RE %%EndProlog %%Page: 1 1 %%BeginPageSetup BP %%EndPageSetup /F0 10/Times-Roman@0 SF(RE_FORMA)72 48 Q 100.405 1.666(T\(7\) S)-1.11 H (ystem Reference Manual)-1.666 E(RE_FORMA)106.237 E 1.666(T\(7\))-1.11 G /F1 10/Times-Bold@0 SF -.2(NA)72 108 S(ME).2 E/F2 10/Courier-Bold@0 SF (re_format)102 120 Q F0 2.52.5 G(OSIX 1003.2 re)-2.5 E(gular e) -.15 E(xpressions)-.15 E F1(DESCRIPTION)72 144 Q F0(Re)102 156 Q .514 (gular e)-.15 F .514(xpressions \(`)-.15 F(`RE')-.74 E -.55('s)-.74 G .513(\), as de\214ned in POSIX 1003.2, come in tw).55 F 3.013(of)-.1 G .513(orms: modern REs \(roughly those)-3.013 F(of)102 168 Q/F3 10 /Courier@0 SF(egrep)2.947 E F0 3.394(\(1\); 1003.2)B .447(calls these `) 2.947 F(`e)-.74 E(xtended')-.15 E 2.948('R)-.74 G .448 (Es\) and obsolete REs \(roughly those of)-2.948 F F3(ed)2.948 E F0 3.396(\(1\); 1003.2)B -.74(``)2.948 G(ba-).74 E(sic')102 180 Q 3.42('R) -.74 G 3.42(Es\). Obsolete)-3.42 F .92(REs mostly e)3.42 F .92 (xist for backw)-.15 F .92(ard compatibility in some old programs; the) -.1 F 3.42(yw)-.15 G .92(ill be dis-)-3.42 F 1.246(cussed at the end.) 102 192 R 1.246(1003.2 lea)6.246 F -.15(ve)-.2 G 3.746(ss).15 G 1.247 (ome aspects of RE syntax and semantics open; `\207' marks decisions on) -3.746 F(these aspects that may not be fully portable to other 1003.2 i\ mplementations.)102 204 Q 3.481(A\()102 222 S .981 (modern\) RE is one\207 or more non-empty\207)-3.481 F/F4 10 /Times-Italic@0 SF(br)3.481 E(anc)-.15 E(hes)-.15 E F0 3.481(,s)C .981 (eparated by `|'.)-3.481 F .98(It matches an)5.98 F .98 (ything that matches)-.15 F(one of the branches.)102 234 Q 2.806(Ab)102 252 S .306(ranch is one\207 or more)-2.806 F F4(pieces)2.806 E F0 2.806 (,c)C 2.806(oncatenated. It)-2.806 F .307 (matches a match for the \214rst, follo)2.806 F .307 (wed by a match for the)-.25 F(second, etc.)102 264 Q 2.706(Ap)102 282 S .206(iece is an)-2.706 F F4(atom)2.706 E F0 .206(possibly follo)2.706 F .206(wed by a single\207 `)-.25 F/F5 10/Symbol SF(*)A F0 .206 (', `+', `?', or)B F4(bound)2.706 E F0 2.706(.A)C 2.705(na)-2.706 G .205 (tom follo)-2.705 F .205(wed by `)-.25 F F5(*)A F0 2.705('m)C .205 (atches a)-2.705 F 1.246(sequence of 0 or more matches of the atom.)102 294 R 1.246(An atom follo)6.246 F 1.247 (wed by `+' matches a sequence of 1 or more)-.25 F(matches of the atom.) 102 306 Q(An atom follo)5 E (wed by `?' matches a sequence of 0 or 1 matches of the atom.)-.25 E(A) 102 324 Q F4(bound)2.596 E F0 .096(is `{' follo)2.596 F .096 (wed by an unsigned decimal inte)-.25 F(ger)-.15 E 2.596(,p)-.4 G .096 (ossibly follo)-2.596 F .096(wed by `,)-.25 F 2.596('p)-.7 G .096 (ossibly follo)-2.596 F .095(wed by anoth-)-.25 F .702 (er unsigned decimal inte)102 336 R(ger)-.15 E 3.202(,a)-.4 G -.1(lwa) -3.202 G .702(ys follo).1 F .702(wed by `}'.)-.25 F .702(The inte)5.702 F .702(gers must lie between 0 and RE_DUP_MAX)-.15 F .616 (\(255\207\) inclusi)102 348 R -.15(ve)-.25 G 3.116(,a).15 G .616 (nd if there are tw)-3.116 F 3.116(oo)-.1 G 3.116(ft)-3.116 G .615 (hem, the \214rst may not e)-3.116 F .615(xceed the second.)-.15 F .615 (An atom follo)5.615 F .615(wed by a)-.25 F .016 (bound containing one inte)102 360 R(ger)-.15 E F4(i)2.517 E F0 .017 (and no comma matches a sequence of e)2.517 F(xactly)-.15 E F4(i)2.517 E F0 .017(matches of the atom.)2.517 F .017(An atom)5.017 F(follo)102 372 Q .536(wed by a bound containing one inte)-.25 F(ger)-.15 E F4(i)3.036 E F0 .535(and a comma matches a sequence of)3.036 F F4(i)3.035 E F0 .535 (or more matches of the)3.035 F 2.594(atom. An)102 384 R .094 (atom follo)2.594 F .094(wed by a bound containing tw)-.25 F 2.594(oi) -.1 G(nte)-2.594 E(gers)-.15 E F4(i)2.594 E F0(and)2.595 E F4(j)2.595 E F0 .095(matches a sequence of)2.595 F F4(i)2.595 E F0(through)2.595 E F4 (j)2.595 E F0(\(inclu-)2.595 E(si)102 396 Q -.15(ve)-.25 G 2.5(\)m).15 G (atches of the atom.)-2.5 E(An)102 414 Q F4(atom)2.907 E F0 .406 (is a re)2.907 F .406(gular e)-.15 F .406 (xpression enclosed in `\(\)' \(matching a match for the re)-.15 F .406 (gular e)-.15 F .406(xpression\), an empty set)-.15 F .622 (of `\(\)' \(matching the null string\)\207, a)102 426 R F4(br)3.122 E (ac)-.15 E -.1(ke)-.2 G 3.122(te).1 G(xpr)-3.322 E(ession)-.37 E F0 .623 (\(see belo)3.123 F .623(w\), `.)-.25 F 5.623('\()-.7 G .623 (matching an)-5.623 F 3.123(ys)-.15 G .623(ingle character\), `^')-3.123 F .676(\(matching the null string at the be)102 438 R .676(ginning of a\ line\), `$' \(matching the null string at the end of a line\), a `\\') -.15 F(follo)102 450 Q .205(wed by one of the characters `^.[$\(\)|)-.25 F F5(*)A F0 .206(+?{\\' \(matching that character tak)B .206 (en as an ordinary character\), a `\\')-.1 F(follo)102 462 Q .209 (wed by an)-.25 F 2.709(yo)-.15 G .209 (ther character\207 \(matching that character tak)-2.709 F .209 (en as an ordinary character)-.1 F 2.709(,a)-.4 G 2.709(si)-2.709 G 2.709(ft)-2.709 G .208(he `\\' had not)-2.709 F .344(been present\207\)\ , or a single character with no other signi\214cance \(matching that ch\ aracter\).)102 474 R 2.845(A`)5.345 G .345({' follo)-2.845 F .345 (wed by)-.25 F 3.133(ac)102 486 S .633 (haracter other than a digit is an ordinary character)-3.133 F 3.132(,n) -.4 G .632(ot the be)-3.132 F .632(ginning of a bound\207.)-.15 F .632 (It is ille)5.632 F -.05(ga)-.15 G 3.132(lt).05 G 3.132(oe)-3.132 G .632 (nd an)-3.132 F(RE with `\\'.)102 498 Q(A)102 516 Q F4(br)3.323 E(ac) -.15 E -.1(ke)-.2 G 3.323(te).1 G(xpr)-3.523 E(ession)-.37 E F0 .823 (is a list of characters enclosed in `[]'.)3.323 F .824 (It normally matches an)5.824 F 3.324(ys)-.15 G .824 (ingle character from)-3.324 F .672(the list \(b)102 528 R .672 (ut see belo)-.2 F 3.172(w\). If)-.25 F .672(the list be)3.172 F .672 (gins with `^', it matches an)-.15 F 3.172(ys)-.15 G .672 (ingle character \(b)-3.172 F .672(ut see belo)-.2 F(w\))-.25 E F4(not) 3.172 E F0(from)3.172 E .896(the rest of the list.)102 540 R .897(If tw) 5.897 F 3.397(oc)-.1 G .897(haracters in the list are separated by `\ \255', this is shorthand for the full)-3.397 F F4 -.15(ra)3.397 G(ng).15 E(e)-.1 E F0(of)3.397 E .64(characters between those tw)102 552 R 3.14 (o\()-.1 G(inclusi)-3.14 E -.15(ve)-.25 G 3.14(\)i).15 G 3.139(nt)-3.14 G .639(he collating sequence, e.g., `[0-9]' in ASCII matches an)-3.139 F 3.139(yd)-.15 G(eci-)-3.139 E 1.662(mal digit.)102 564 R 1.662 (It is ille)6.662 F -.05(ga)-.15 G 1.662(l\207 for tw).05 F 4.162(or)-.1 G 1.662(anges to share an endpoint, e.g., `a-c-e'.)-4.162 F 1.663 (Ranges are v)6.663 F 1.663(ery collating-se-)-.15 F (quence-dependent, and portable programs should a)102 576 Q -.2(vo)-.2 G (id relying on them.).2 E 1.69 -.8(To i)102 594 T .09 (nclude a literal `]' in the list, mak).8 F 2.59(ei)-.1 G 2.59(tt)-2.59 G .09(he \214rst character \(follo)-2.59 F .09(wing a possible `^'\).) -.25 F 1.69 -.8(To i)5.09 H .09(nclude a literal `\255',).8 F(mak)102 606 Q 2.91(ei)-.1 G 2.91(tt)-2.91 G .41(he \214rst or last character) -2.91 F 2.91(,o)-.4 G 2.91(rt)-2.91 G .41 (he second endpoint of a range.)-2.91 F 2.01 -.8(To u)5.41 H .41 (se a literal `\255' as the \214rst endpoint).8 F .568 (of a range, enclose it in `[.)102 618 R 3.068('a)-.7 G .568 (nd `.]' to mak)-3.068 F 3.068(ei)-.1 G 3.068(tac)-3.068 G .567 (ollating element \(see belo)-3.068 F 3.067(w\). W)-.25 F .567 (ith the e)-.4 F .567(xception of these)-.15 F .734 (and some combinations using `[' \(see ne)102 630 R .735(xt paragraphs\ \), all other special characters, including `\\', lose their)-.15 F (special signi\214cance within a brack)102 642 Q(et e)-.1 E(xpression.) -.15 E -.4(Wi)102 660 S .4(thin a brack).4 F .4(et e)-.1 F .4 (xpression, a collating element \(a character)-.15 F 2.899(,am)-.4 G .399(ulti-character sequence that collates as if it)-2.899 F .961 (were a single character)102 672 R 3.461(,o)-.4 G 3.461(rac)-3.461 G .961(ollating-sequence name for either\) enclosed in `[.)-3.461 F 3.461 ('a)-.7 G .961(nd `.]' stands for the se-)-3.461 F .488 (quence of characters of that collating element.)102 684 R .487 (The sequence is a single element of the brack)5.488 F .487(et e)-.1 F (xpression')-.15 E(s)-.55 E 2.643(list. A)102 696 R(brack)2.643 E .143 (et e)-.1 F .143(xpression containing a multi-character collating eleme\ nt can thus match more than one char)-.15 F(-)-.2 E(acter)102 708 Q 3.466(,e)-.4 G .966(.g., if the collating sequence includes a `ch' coll\ ating element, then the RE `[[.ch.]])-3.466 F F5(*)A F0 .965 (c' matches the)B(BSD Experimental)72 756 Q(March 20, 1994)126.37 E(1) 197.2 E EP %%Page: 2 2 %%BeginPageSetup BP %%EndPageSetup /F0 10/Times-Roman@0 SF(RE_FORMA)72 48 Q 100.405 1.666(T\(7\) S)-1.11 H (ystem Reference Manual)-1.666 E(RE_FORMA)106.237 E 1.666(T\(7\))-1.11 G (\214rst \214v)102 96 Q 2.5(ec)-.15 G(haracters of `chchcc'.)-2.5 E -.4 (Wi)102 114 S .81(thin a brack).4 F .81(et e)-.1 F .81 (xpression, a collating element enclosed in `[=' and `=]' is an equi) -.15 F -.25(va)-.25 G .81(lence class, standing).25 F .441 (for the sequences of characters of all collating elements equi)102 126 R -.25(va)-.25 G .44(lent to that one, including itself.).25 F .44 (\(If there are)5.44 F .521(no other equi)102 138 R -.25(va)-.25 G .522 (lent collating elements, the treatment is as if the enclosing delimite\ rs were `[.).25 F 3.022('a)-.7 G .522(nd `.]'.\))-3.022 F -.15(Fo)5.522 G(r).15 E -.15(ex)102 150 S .197(ample, if o and o).15 F 3.532(^a)-4.165 G .196(re the members of an equi)-3.532 F -.25(va)-.25 G .196 (lence class, then `[[=o=]]', `[[=o).25 F .835(^=)-4.165 G .196 (]]', and `[oo)-.835 F .835(^])-4.165 G 2.696('a)-.835 G .196 (re all syn-)-2.696 F(on)102 162 Q 2.5(ymous. An)-.15 F(equi)2.5 E -.25 (va)-.25 G(lence class may not\207 be an endpoint of a range.).25 E -.4 (Wi)102 180 S .715(thin a brack).4 F .715(et e)-.1 F .715 (xpression, the name of a)-.15 F/F1 10/Times-Italic@0 SF -.15(ch)3.215 G (ar).15 E .715(acter class)-.15 F F0 .716 (enclosed in `[:' and `:]' stands for the list of all)3.215 F (characters belonging to that class.)102 192 Q (Standard character class names are:)5 E 8.5(alnum digit)132 210 R (punct)17.66 E 11.84(alpha graph)132 222 R(space)13.23 E 11.28(blank lo) 132 234 R 10.98(wer upper)-.25 F 15.17(cntrl print)132 246 R(xdigit) 17.11 E .552(These stand for the character classes de\214ned in)102 264 R/F2 10/Courier@0 SF(ctype)3.052 E F0 3.604(\(3\). A)B .552 (locale may pro)3.052 F .551(vide others.)-.15 F 3.051(Ac)5.551 G .551 (haracter class)-3.051 F(may not be used as an endpoint of a range.)102 276 Q .515(There are tw)102 294 R 3.015(os)-.1 G .515 (pecial cases\207 of brack)-3.015 F .515(et e)-.1 F .515 (xpressions: the brack)-.15 F .515(et e)-.1 F .516 (xpressions `[[:<:]]' and `[[:>:]]' match the)-.15 F .23 (null string at the be)102 306 R .23(ginning and end of a w)-.15 F .23 (ord respecti)-.1 F -.15(ve)-.25 G(ly).15 E 5.23(.A)-.65 G -.1(wo)-2.5 G .23(rd is de\214ned as a sequence of w).1 F .23(ord charac-)-.1 F .456 (ters which is neither preceded nor follo)102 318 R .456(wed by w)-.25 F .456(ord characters.)-.1 F 2.957(Aw)5.457 G .457(ord character is an) -3.057 F F1(alnum)2.957 E F0 .457(character \(as)2.957 F .462 (de\214ned by)102 330 R F2(ctype)2.962 E F0 3.423(\(3\)\) or)B .461 (an underscore.)2.961 F .461(This is an e)5.461 F .461 (xtension, compatible with b)-.15 F .461(ut not speci\214ed by POSIX)-.2 F(1003.2, and should be used with caution in softw)102 342 Q (are intended to be portable to other systems.)-.1 E .289(In the e)102 360 R -.15(ve)-.25 G .289 (nt that an RE could match more than one substring of a gi).15 F -.15 (ve)-.25 G 2.79(ns).15 G .29(tring, the RE matches the one start-)-2.79 F .277(ing earliest in the string.)102 372 R .276(If the RE could match\ more than one substring starting at that point, it matches the)5.277 F 3.222(longest. Sube)102 384 R .722(xpressions also match the longest po\ ssible substrings, subject to the constraint that the whole)-.15 F .271 (match be as long as possible, with sube)102 396 R .27 (xpressions starting earlier in the RE taking priority o)-.15 F -.15(ve) -.15 G 2.77(ro).15 G .27(nes starting)-2.77 F(later)102 408 Q 5.99(.N) -.55 G .99(ote that higher)-5.99 F(-le)-.2 E -.15(ve)-.25 G 3.491(ls).15 G(ube)-3.491 E .991(xpressions thus tak)-.15 F 3.491(ep)-.1 G .991 (riority o)-3.491 F -.15(ve)-.15 G 3.491(rt).15 G .991(heir lo)-3.491 F (wer)-.25 E(-le)-.2 E -.15(ve)-.25 G 3.491(lc).15 G .991(omponent sube) -3.491 F(xpres-)-.15 E(sions.)102 420 Q .348 (Match lengths are measured in characters, not collating elements.)102 438 R 2.848(An)5.348 G .348(ull string is considered longer than no) -2.848 F 9.587(match at all.)102 450 R -.15(Fo)14.587 G 12.087(re).15 G 9.587(xample, `bb)-12.237 F/F3 10/Symbol SF(*)A F0 12.087('m)C 9.588 (atches the three middle characters of `abbbc',)-12.087 F 1.641(`\(wee|\ week\)\(knights|nights\)' matches all ten characters of `weeknights', w\ hen `\(.)102 462 R F3(*)A F0(\).)A F3(*)A F0 4.141('i)C 4.141(sm)-4.141 G 1.64(atched ag)-4.141 F(ainst)-.05 E .297 (`abc' the parenthesized sube)102 474 R .298 (xpression matches all three characters, and when `\(a)-.15 F F3(*)A F0 (\))A F3(*)A F0 2.798('i)C 2.798(sm)-2.798 G .298(atched ag)-2.798 F .298(ainst `bc')-.05 F(both the whole RE and the parenthesized sube)102 486 Q(xpression match the null string.)-.15 E .276 (If case-independent matching is speci\214ed, the ef)102 504 R .276 (fect is much as if all case distinctions had v)-.25 F .275 (anished from the)-.25 F 2.71(alphabet. When)102 516 R .21 (an alphabetic that e)2.71 F .21(xists in multiple cases appears as an \ ordinary character outside a brack)-.15 F(et)-.1 E -.15(ex)102 528 S 1.149(pression, it is ef).15 F(fecti)-.25 E -.15(ve)-.25 G 1.149 (ly transformed into a brack).15 F 1.149(et e)-.1 F 1.148 (xpression containing both cases, e.g., `x' becomes)-.15 F 3.118 (`[xX]'. When)102 540 R .618(it appears inside a brack)3.118 F .618 (et e)-.1 F .618 (xpression, all case counterparts of it are added to the brack)-.15 F .619(et e)-.1 F(x-)-.15 E(pression, so that \(e.g.\) `[x]' becomes `[xX\ ]' and `[^x]' becomes `[^xX]'.)102 552 Q .657 (No particular limit is imposed on the length of REs\207.)102 570 R .657 (Programs intended to be portable should not emplo)5.657 F(y)-.1 E .452 (REs longer than 256 bytes, as an implementation can refuse to accept s\ uch REs and remain POSIX-compli-)102 582 R(ant.)102 594 Q .253 (Obsolete \(`)102 612 R(`basic')-.74 E .253('\) re)-.74 F .253(gular e) -.15 F .253(xpressions dif)-.15 F .253(fer in se)-.25 F -.15(ve)-.25 G .253(ral respects.).15 F .252 (`|', `+', and `?' are ordinary characters and)5.253 F .44 (there is no equi)102 624 R -.25(va)-.25 G .44 (lent for their functionality).25 F 5.44(.T)-.65 G .44 (he delimiters for bounds are `\\{' and `\\}', with `{' and `}' by)-5.44 F(themselv)102 636 Q .674(es ordinary characters.)-.15 F .674 (The parentheses for nested sube)5.674 F .673 (xpressions are `\\\(' and `\\\)', with `\(' and `\)')-.15 F .321 (by themselv)102 648 R .321(es ordinary characters.)-.15 F .322 (`^' is an ordinary character e)5.321 F .322(xcept at the be)-.15 F .322 (ginning of the RE or\207 the be-)-.15 F .092 (ginning of a parenthesized sube)102 660 R .092 (xpression, `$' is an ordinary character e)-.15 F .091 (xcept at the end of the RE or\207 the end)-.15 F .413 (of a parenthesized sube)102 672 R .413(xpression, and `)-.15 F F3(*)A F0 2.913('i)C 2.913(sa)-2.913 G 2.913(no)-2.913 G .413 (rdinary character if it appears at the be)-2.913 F .414 (ginning of the RE or)-.15 F .633(the be)102 684 R .633 (ginning of a parenthesized sube)-.15 F .633 (xpression \(after a possible leading `^'\).)-.15 F(Finally)5.632 E 3.132(,t)-.65 G .632(here is one ne)-3.132 F 3.132(wt)-.25 G(ype)-3.132 E .532(of atom, a)102 696 R F1(bac)3.032 E 3.032(kr)-.2 G(efer)-3.402 E (ence)-.37 E F0 3.033(:`)C .533(\\' follo)-3.033 F .533 (wed by a non-zero decimal digit)-.25 F F1(d)3.033 E F0 .533 (matches the same sequence of charac-)3.033 F 1.433(ters matched by the) 102 708 R F1(d)3.933 E F0 1.433(th parenthesized sube)B 1.433 (xpression \(numbering sube)-.15 F 1.433 (xpressions by the positions of their)-.15 F(BSD Experimental)72 756 Q (March 20, 1994)126.37 E(2)197.2 E EP %%Page: 3 3 %%BeginPageSetup BP %%EndPageSetup /F0 10/Times-Roman@0 SF(RE_FORMA)72 48 Q 100.405 1.666(T\(7\) S)-1.11 H (ystem Reference Manual)-1.666 E(RE_FORMA)106.237 E 1.666(T\(7\))-1.11 G (opening parentheses, left to right\), so that \(e.g.\) `\\\([bc]\\\)\\\ 1' matches `bb' or `cc' b)102 96 Q(ut not `bc'.)-.2 E/F1 10/Times-Bold@0 SF 1.666(SEE ALSO)72 120 R/F2 10/Courier@0 SF(regex)102 132 Q F0(\(3\))A (POSIX 1003.2, section 2.8 \(Re)102 150 Q(gular Expression Notation\).) -.15 E F1 -.1(BU)72 174 S(GS).1 E F0(Ha)102 186 Q(ving tw)-.2 E 2.5(ok) -.1 G(inds of REs is a botch.)-2.5 E .23(The current 1003.2 spec says t\ hat `\)' is an ordinary character in the absence of an unmatched `\('; \ this w)102 204 R .231(as an)-.1 F(unintentional result of a w)102 216 Q (ording error)-.1 E 2.5(,a)-.4 G(nd change is lik)-2.5 E(ely)-.1 E 5(.A) -.65 G -.2(vo)-5.74 G(id relying on it.).2 E 1.064 (Back references are a dreadful botch, posing major problems for ef)102 234 R 1.063(\214cient implementations.)-.25 F(The)6.063 E 3.563(ya)-.15 G 1.063(re also)-3.563 F(some)102 246 Q(what v)-.25 E (aguely de\214ned \(does `a\\\(\\\(b\\\))-.25 E/F3 10/Symbol SF(*)A F0 (\\2\\\))A F3(*)A F0(d' match `abbbd'?\).)A -1.22 -.74(Av o)5 H (id using them.).74 E(1003.2')102 264 Q 3.467(ss)-.55 G .967 (peci\214cation of case-independent matching is v)-3.467 F 3.468 (ague. The)-.25 F -.74(``)3.468 G .968(one case implies all cases').74 F 3.468('d)-.74 G(e\214nition)-3.468 E(gi)102 276 Q -.15(ve)-.25 G 2.5(na) .15 G(bo)-2.5 E .3 -.15(ve i)-.15 H 2.5(sc).15 G (urrent consensus among implementors as to the right interpretation.) -2.5 E(The syntax for w)102 294 Q(ord boundaries is incredibly ugly)-.1 E(.)-.65 E(BSD Experimental)72 750 Q(March 20, 1994)126.37 E(3)197.2 E EP %%Trailer end %%EOF sma-1.4.orig/docs/re_format.txt0000644000175000017500000002415507603333514016751 0ustar apollockapollock RE FORMAT(7) System Reference Manual RE FORMAT(7) NAME re format - POSIX 1003.2 regular expressions DESCRIPTION Regular expressions (``RE''s), as defined in POSIX 1003.2, come in two forms: modern REs (roughly those of egrep(1); 1003.2 calls these ``ex- tended'' REs) and obsolete REs (roughly those of ed(1); 1003.2 ``basic'' REs). Obsolete REs mostly exist for backward compatibility in some old programs; they will be discussed at the end. 1003.2 leaves some aspects of RE syntax and semantics open; `' marks decisions on these aspects that may not be fully portable to other 1003.2 implementations. A (modern) RE is one or more non-empty branches, separated by `|'. It matches anything that matches one of the branches. A branch is one or more pieces, concatenated. It matches a match for the first, followed by a match for the second, etc. A piece is an atom possibly followed by a single `*', `+', `?', or bound. An atom followed by `*' matches a sequence of 0 or more matches of the atom. An atom followed by `+' matches a sequence of 1 or more matches of the atom. An atom followed by `?' matches a sequence of 0 or 1 matches of the atom. A bound is `{' followed by an unsigned decimal integer, possibly followed by `,' possibly followed by another unsigned decimal integer, always fol- lowed by `}'. The integers must lie between 0 and RE DUP MAX (255) in- clusive, and if there are two of them, the first may not exceed the sec- ond. An atom followed by a bound containing one integer i and no comma matches a sequence of exactly i matches of the atom. An atom followed by a bound containing one integer i and a comma matches a sequence of i or more matches of the atom. An atom followed by a bound containing two in- tegers i and j matches a sequence of i through j (inclusive) matches of the atom. An atom is a regular expression enclosed in `()' (matching a match for the regular expression), an empty set of `()' (matching the null string), a bracket expression (see below), `.' (matching any single character), `^' (matching the null string at the beginning of a line), `$' (matching the null string at the end of a line), a `\' followed by one of the char- acters `^.[$()|*+?{\' (matching that character taken as an ordinary char- acter), a `\' followed by any other character (matching that character taken as an ordinary character, as if the `\' had not been present), or a single character with no other significance (matching that character). A `{' followed by a character other than a digit is an ordinary character, not the beginning of a bound. It is illegal to end an RE with `\'. A bracket expression is a list of characters enclosed in `[]'. It nor- mally matches any single character from the list (but see below). If the list begins with `^', it matches any single character (but see below) not from the rest of the list. If two characters in the list are separated by `-', this is shorthand for the full range of characters between those two (inclusive) in the collating sequence, e.g., `[0-9]' in ASCII matches any decimal digit. It is illegal for two ranges to share an endpoint, e.g., `a-c-e'. Ranges are very collating-sequence-dependent, and portable programs should avoid relying on them. To include a literal `]' in the list, make it the first character (fol- lowing a possible `^'). To include a literal `-', make it the first or last character, or the second endpoint of a range. To use a literal `-' as the first endpoint of a range, enclose it in `[.' and `.]' to make it a collating element (see below). With the exception of these and some combinations using `[' (see next paragraphs), all other special charac- ters, including `\', lose their special significance within a bracket ex- pression. Within a bracket expression, a collating element (a character, a multi- character sequence that collates as if it were a single character, or a collating-sequence name for either) enclosed in `[.' and `.]' stands for the sequence of characters of that collating element. The sequence is a single element of the bracket expression's list. A bracket expression containing a multi-character collating element can thus match more than one character, e.g., if the collating sequence includes a `ch' collating element, then the RE `[[.ch.]]*c' matches the first five characters of `chchcc'. Within a bracket expression, a collating element enclosed in `[=' and `=]' is an equivalence class, standing for the sequences of characters of all collating elements equivalent to that one, including itself. (If there are no other equivalent collating elements, the treatment is as if the enclosing delimiters were `[.' and `.]'.) For example, if o and o are the members of an equivalence class, then `[[=o=]]', `[[=o=]]', and `[oo]' are all synonymous. An equivalence class may not be an endpoint of a range. Within a bracket expression, the name of a character class enclosed in `[:' and `:]' stands for the list of all characters belonging to that class. Standard character class names are: alnum digit punct alpha graph space blank lower upper cntrl print xdigit These stand for the character classes defined in ctype(3). A locale may provide others. A character class may not be used as an endpoint of a range. There are two special cases of bracket expressions: the bracket expres- sions `[[:<:]]' and `[[:>:]]' match the null string at the beginning and end of a word respectively. A word is defined as a sequence of word characters which is neither preceded nor followed by word characters. A word character is an alnum character (as defined by ctype(3)) or an un- derscore. This is an extension, compatible with but not specified by POSIX 1003.2, and should be used with caution in software intended to be portable to other systems. In the event that an RE could match more than one substring of a given string, the RE matches the one starting earliest in the string. If the RE could match more than one substring starting at that point, it matches the longest. Subexpressions also match the longest possible substrings, subject to the constraint that the whole match be as long as possible, with subexpressions starting earlier in the RE taking priority over ones starting later. Note that higher-level subexpressions thus take priority over their lower-level component subexpressions. Match lengths are measured in characters, not collating elements. A null string is considered longer than no match at all. For example, `bb*' matches the three middle characters of `abbbc', `(wee|week)(knights|nights)' matches all ten characters of `weeknights', when `(.*).*' is matched against `abc' the parenthesized subexpression matches all three characters, and when `(a*)*' is matched against `bc' both the whole RE and the parenthesized subexpression match the null string. If case-independent matching is specified, the effect is much as if all case distinctions had vanished from the alphabet. When an alphabetic that exists in multiple cases appears as an ordinary character outside a bracket expression, it is effectively transformed into a bracket expres- sion containing both cases, e.g., `x' becomes `[xX]'. When it appears inside a bracket expression, all case counterparts of it are added to the bracket expression, so that (e.g.) `[x]' becomes `[xX]' and `[^x]' be- comes `[^xX]'. No particular limit is imposed on the length of REs. Programs intended to be portable should not employ REs longer than 256 bytes, as an imple- mentation can refuse to accept such REs and remain POSIX-compliant. Obsolete (``basic'') regular expressions differ in several respects. `|', `+', and `?' are ordinary characters and there is no equivalent for their functionality. The delimiters for bounds are `\{' and `\}', with `{' and `}' by themselves ordinary characters. The parentheses for nest- ed subexpressions are `\(' and `\)', with `(' and `)' by themselves ordi- nary characters. `^' is an ordinary character except at the beginning of the RE or the beginning of a parenthesized subexpression, `$' is an ordi- nary character except at the end of the RE or the end of a parenthesized subexpression, and `*' is an ordinary character if it appears at the be- ginning of the RE or the beginning of a parenthesized subexpression (af- ter a possible leading `^'). Finally, there is one new type of atom, a back reference: `\' followed by a non-zero decimal digit d matches the same sequence of characters matched by the dth parenthesized subexpres- sion (numbering subexpressions by the positions of their opening paren- theses, left to right), so that (e.g.) `\([bc]\)\1' matches `bb' or `cc' but not `bc'. SEE ALSO regex(3) POSIX 1003.2, section 2.8 (Regular Expression Notation). BUGS Having two kinds of REs is a botch. The current 1003.2 spec says that `)' is an ordinary character in the ab- sence of an unmatched `('; this was an unintentional result of a wording error, and change is likely. Avoid relying on it. Back references are a dreadful botch, posing major problems for efficient implementations. They are also somewhat vaguely defined (does `a\(\(b\)*\2\)*d' match `abbbd'?). Avoid using them. 1003.2's specification of case-independent matching is vague. The ``one case implies all cases'' definition given above is current consensus among implementors as to the right interpretation. The syntax for word boundaries is incredibly ugly. BSD Experimental March 20, 1994 3 sma-1.4.orig/docs/sma.80000644000175000017500000002252307642602717015107 0ustar apollockapollock.Dd October 28, 2001 .Dt SMA 8 .Os .Sh NAME .Nm sma .Nd Sendmail Log Analyser .Sh SYNOPSIS .Nm sma .Op Nm OPTIONS .Op Ar .Sh DESCRIPTION The .Nm utility analyses sendmail log entries and produces a summary of mail activity. .Nm reads the input from .Ar file or from standard input and writes the report to standard output or file. .Pp .Nm can be configured using command line options or configuration file, or both. Command line options always override the configuration file. .Pp The available command line options are as follows: .Bl -tag -width Ds .It Fl A Downcase all addresses. This is so that foo@bar.com is equivilant to FOO@BAR.Com and Foo@Bar.com and they all get counted the same in the counts. Usually one is interested in the user, not the format of the address and since email addresses are case insensitive to MTAs, one may want to make them case insensitive in .Nm .It Fl a Format the report as ASCII. .It Fl b Ar color Set the background color of the HTML report as .Ar color. .It Fl C Ar string Set report header as .Ar string. .It Fl D Ar date1,date2 Process log entry only if the date is between .Ar date1 and .Ar date2. The format of the date is as follows: .Sm off .Oo Oo Oo Oo Oo Oo .Ar cc Oc .Ar yy Oc .Ar mm Oc .Ar dd Oc .Ar HH Oc .Ar MM Op Ar \&.SS Oc .Sm on where .Pp .Bl -tag -width Ds -compact -offset indent .It Ar yy Year in abbreviated form (for years 1969-2068). The format .Ar ccyymmddHHMM is also permitted, for non-ambiguous years. .It Ar mm Numeric month, a number from 1 to 12. .It Ar dd Day, a number from 1 to 31. .It Ar HH Hour, a number from 0 to 23. .It Ar MM Minute, a number from 0 to 59. .It Ar SS Second, a number from 0 to 61 (59 plus a maximum of two leap seconds). .El .Pp Everything but the minute is optional. The dates must be separated using a colon, without any whitespace characters. If either of the dates is missing, current date is used. .Pp .It Fl c Print the copyright notice and exit. .It Fl d Process only the domain portion of email address. .It Fl f Ar file Read the configuration from .Ar file instead of the default configuration file. The default configuration file is defined in conf.h. .It Fl F Do not use default configuration file even if it exists. .It Fl H Ar name Use .Ar name as hostname. .It Fl L Ar string Process only lines with syslog tag .Ar string .It Fl h Print help message and exit. .It Fl i Include the ASCII report as HTML comment (requires -w or -O html). .It Fl n Do not report the time distribution. .It Fl o Ar file Print the report as .Ar file. If not given, print to stdout. .It Fl O Ar format Format the report as .Ar format. Possible values for .Ar format are ascii, html and clog. .It Fl p Print current configuration to stdout. .It Fl s Sort by transfers. Default is by number of messages. .It Fl t Ar value Adjust the internal hash table size. Possible values for .Ar value are normal, big and huge. .It Fl q Do not print any warning messages. .It Fl l Ar num Number of the top senders and recipients in the report. Default is 10. .It Fl r Ar num Number of the top relay senders and recipients in the report. Default is 5. .It Fl v Print some debugging information for each parsed line. .It Fl w Format the report as HTML. .Sh KEYWORDS .Nm configuration file consists of keyword-value pairs. Available configuration file keywords and values are listed below. .Pp .Bl -tag -width indent .It Nm BgColor Ar RGB Set HTML report background color as .Ar RGB. Command line option: .Fl b .It Nm BounceAddress Ar string Set error message bounce address as .Ar string. .It Nm CaseSensitive Ar value Set filter case sensitivity. Possible values are .Ar yes or .Ar no. This options requires .Nm USE_REGEXP compile time definition. .It Nm DowncaseAddresses Ar value Set whether or not to make all addresses lower case, to make counts for users more accurate. Possible values are .Ar yes or .Ar no. .It Nm ClogFormat Ar string Formatting string for Custom Log format. .Ar format consists of ordinary characters and various two-character sequencies which are replaced with built-in variables as follows: .Bl -tag -width indent .It Nm %U time in UNIX time format .It Nm %D time in form "Wed Jun 30 21:49:08 1993" .It Nm %y year, four digits .It Nm %m month, in digits .It Nm %M month, three letter English .It Nm %n minute .It Nm %s second .It Nm %d day .It Nm %h hour .It Nm %H hostname .It Nm %z size in bytes .It Nm %f envelope sender .It Nm %t envelope recipient .It Nm %F relay sender .It Nm %\T relay recipient .It Nm %S status (1 = sent, 0 = error) .It Nm %\i message id .It Nm %% %-character .It Nm \en newline .It Nm \et tab stop .It Nm \e\e single backslash .El .It Nm ClogSentOnly Ar value If .Ar value is set as .Ar yes , print only sent messages (status = 1). .It Nm Comment Ar string Set report header as .Ar string. Command line option: .Fl C .It Nm Debug Ar value If .Ar value is set as .Ar yes , print debugging information to stderr. Command line option: .Fl v .It Nm EndTime Ar date Process log entry only if the date is before .Ar date. The format of the .Ar date is .Nm YYYY/MM/DD-HH:MM:SS. Command line option: .Fl D .It Nm EnvelopePairs Ar number Set the number of the top envelope pairs as .Ar number. .It Nm EnvelopeRecipientFilter Ar string Set envelope recipient filter as .Ar string. If .Nm sma is compiled with .Nm USE_REGEXP , .Ar string can be regular expression of syntax defined in re_format(7). Otherwise the standard C library function strstr() is used. If the first character of .Ar string is '!', filter is reversed. .It Nm EnvelopeRecipients Ar number Set the number of the top envelope recipients as .Ar number. Command line option: .Fl l .It Nm EnvelopeSenderFilter Ar string Set envelope sender filter as .Ar string. See also .Nm EnvelopeRecipientFilter keyword. .It Nm EnvelopeSenders Ar number Set the number of the top envelope senders as .Ar number. Command line option: .Fl l .It Nm FooterText Ar string Set report footer as .Ar string. .It Nm Format Ar string Set the output format as .Ar string. Possible values are .Ar ascii , .Ar html and .Ar clog. Command line options: .Fl a , .Fl w and .Fl O .It Nm HashTables Ar string Adjust the internal hash table size. Possible values are .Ar normal , .Ar big and .Ar huge. It is also possible to specify a custom hash table size by defining two values and separating them with a comma ','. Command line option: .Fl t .It Nm HeaderText Ar string Set report header as .Ar string. .It Nm HostName Ar string Set the hostname as .Ar string. Normally, HostName is taken from log files, or, in case of Sendmail for NT, from the compile time define HOSTNAME. Command line option: .Fl H .It Nm IncludeAscii Ar value Include the ASCII report as HTML comment. Possible values are .Ar yes or .Ar no. Command line option: .Fl i .It Nm OutFile Ar file Print the report as .Ar file. Command line option: .Fl o .It Nm PictureALT Ar string If .Nm PictureURL is defined, set ALT text inside the IMG HTML-tag as .Ar string. .It Nm PictureLink Ar string If .Nm PictureURL is defined, make the picture as link pointing to .Ar string. .It Nm PictureParameters Ar string If .Nm PictureURL is defined, set additional IMG parameters as .Ar string. .It Nm PictureURL Ar URL Include a picture with source URL as .Ar URL in HTML report. The picture appears in a upper left corner of the page. See also .Nm PictureParameters , .Nm PictureALT and .Nm PictureLink keywords. .It Nm PrintGeneralInfo Ar value Print the General Information section in report. Possible values are .Ar yes or .Ar no. .It Nm PrintStatus Ar number Set the number of the top status messages as .Ar number. .It Nm PrintRule Ar number Set the number of the top ruleset rejections as .Ar number. .It Nm PrintTime Ar value Print the Time Distribution section in report. Possible values are .Ar yes or .Ar no. Command line option: .Fl n .It Nm RelayPairs Ar number Set the number of the top relay address pairs as .Ar number. .It Nm RelayRecipientFilter Ar string Set relay recipient filter as .Ar string. See also .Nm EnvelopeRecipientFilter keyword. .It Nm RelayRecipients Ar number Set the number of the top relay recipients as .Ar number. Command line option: .Fl r .It Nm RelaySenderFilter Ar string Set relay sender filter as .Ar string. See also .Nm EnvelopeRecipientFilter keyword. .It Nm RelaySenders Ar number Set the number of the top relay senders as .Ar number. Command line option: .Fl r .It Nm ShowUsers Ar value If .Ar value is set as .Ar no , process only the domain portion of the email address. Command line option: .Fl d .It Nm Silent Ar value If .Ar value is set as .Ar yes , do not print error messages. Command line option: .Fl q .It Nm Sorting Ar value Set the sort order as .Ar value. Possible values are .Ar number or .Ar transfer. Command line option: .Fl s .It Nm SyslogTag Ar string Process only lines with syslog tag .Ar string. Command line option: .Fl L .It Nm StartTime Ar date Process log entry only if the date is after .Ar date. The format of the .Ar date is .Nm YYYY/MM/DD-HH:MM:SS. Command line option: .Fl D .It Nm TbColor Ar RGB Set HTML report table corner color as .Ar RGB. .Sh FILES .Nm sma can as an option use a configuration file. It's default location can be configured using a compile time define .Nm DEFAULT_CONF in file conf.h. By default, it is defined as .Nm ./sma.conf .Sh AUTHOR Jarkko Turkulainen .Sh BUGS .Nm takes the year from runtime year. It knows nothing about the new year transitions in log files. .Pp The documentation contains a lot of bad english. sma-1.4.orig/docs/sma.pdf0000644000175000017500000002562307603333514015506 0ustar apollockapollock%PDF-1.2 %Çì¢ 4 0 obj <> stream xœXË’Û¶Ýë+°‹S5D€Ï»s<“š©òØŽ¥,R±I¼áC!AËúÿJþ1IARæ^ÇU™2 tŸî>Ý}0!&(TìÏM½økñ"ú›û±©ÑÏ«ÅOõaµ]!ÎX„VÇA>‡RŠÒ>Õ¯–ϯѧW(CŸ~üqõßE¨e!fy 'Wū婗¢Fϼá;Ñý Q£Õf‘†˜&yfŽõÏöúfAXŽã$Õ–bLíÞ ¼BàN#8IuÖúKq˜0sîÓ«Ì@ùéc:@Õá Šà ‰>úîõä3Â42žÌíÌÞ i‚B5Ìš›uɱ±ÐÛxÿ^ÎÁ©ù(š¢æe…Þ¶;ôºáÕ©‡1(*g¿¿{ÿaù´<ÂÂÛ(fÌ&àó[& Íóoï?¬žÞ¿[ž_fú.à(ÚZùlÍО2hœ›#Û²c|n-ÊfF¼Iœâ<Ë\˜÷Ë7Ÿ4$Ñéj/¼jd˜…‘Ep‘(t+J@=ÒØVdeUÊâ&ñ=ê]9*(‡hdWÂGÞèеŰQAýP×¼;¡v‹ôQ¾‘åHpÈ'&Ìòå ØÖœŒpæ>GæŠpu4¢¶f;Á‹ɽ@esäè;`i†ÈŽÍжkk¯TÀ†œå³*ydIW۩먗=ï ãJ§âØ•Rÿ8´D²ÎµƒTáþ·Jx±À€H¹Hv+\šºp©Mʆ7h-Цm¾í†NhèËf‡2œªlj²l›^¹µç¸ú 0Ü©ëVî5˜Ñ#GÔ²ñÍ5[¼ Ô@MD7OèL¢Ü¥øÈ§–&0šŒ¹qWõ ¦cÚ¿ˆñN3,Ï]Y»²:­~9T‡ E›<à?âÖ 5“†bê|ð™>ì´)+¾®ÄõÜñ öhÛV•FO’p´wìÿã•’ä\94{•Cgj†Øi§l…8[¢«¹œó P¼^¾yzº LMàÏèsí±›Ø…°i«¶;Ç£ZÁ°e[ ãoÍ7îºv€Tè;ª§Õ÷ÇÕóÛ ŒïZœÅ3O>LJsœdSjÞÜ€ÙÃxiv/á´0öÐô¢»D“ÁÂcù™EQó'ðÜßÀSp)Èú?õÛ2™]º3tº&b?ÎJ‰MuB¥É¡²ƒÊZW…h.w†ÚÎLoëÉ»7ìÕNfnÉ>ìG‘#¨FoÀÕ0ÚQm³m5ãÚs †ûÁ4Ni ½,¶áš®HqLs—oh ô‡þÏÃÆ€"£€Ùl¼Ó³8] L»rúŽKuý—Šâ;.=>þ?—l"žŸýK“ ð3x&Nðré—63Â$°zï8²øógtÇŒ¡YŠ)qDÙ‹Nx®ò&ÇÉê§>ÐóßµüïÓø&0Õ©öbGcÞÁªD|½6n"ÕzÌMå¨Vhú2†è$x×#˜(y@Ã䩦0‰§É;ñõZE0iR6òìtªë¢x|ô‚Pe¶Beo¶ #ª4ŽÜ¼ê[t]]J€x§\¢¦m^¯ËÝнŠýÔ±±=|î¹|½jÑ•T·Üß~j†z-¬¼ J;ú/f}v:³÷ü4{0À‚ ‰ù‡;ÞLJ°Û®¾Sßwš€ýúw~Û¡›9¦zÏýŽC嘲 Ç)U›}¬…_=çú¹l)üj£qþ/)ô›ÇÙ[ ÅU{ ‚‚š?Tƒ’¼5ÿZÖC­'æq=£Ø±¯­æËݽÍ?€¨V~zK©êÛl_Ì«-Ë"ÛI®éEw’{¥ôÖî„æÐ«1q5˜=^ę̈!nÄ ¯0ZÙÑÞ£zè¥R½8ðNw Q\/ýæK¹oµº‡?ƒÆ©¥ÔÉàÎAŽ{%ƒ|rjv7R@ §-`NtóõÒ+huÙ+·wh3tìËqñ ½(üme“[ÙÞ™‹ª°ò¥•u,&°íÜÈ=uån/¡•e @•æÓc)…èbwæk)/$CœÁ“eòï7ᙣôî×·ð,jR-J¿B„y'E_ˆt{Cœ\>VBLjsUò„Ò¥Š¾ò2»€6Hé‹>h D·«ªlz©œ¸‹­yYØ£)¬$õ”5ë`¨ä¥ž7äœîêSˆ#¡WîÍ4  OšÄYT4*Ä·F¨‡šº·ÅûýËí’Þ·Š0Š—$Ð!Ê\¿“áÕ(ûsبãÞ7/;3̛ǾGýržÍ‹­þÏXxØî“ó÷RœŒw¿–½¼`¥j"MQ>Þ SÃk¯Ôç,ú­÷UÉpߺ<=œAEîÛ^ª#>¶4Õ¥vÐÞ~÷³à¬åÔ®×# õ§^iqÉw¾ix;¦WÌOý¤…gˆmÿÒ¼Ù‹ê€jÁw³±’CqS¬Dý ÔU¦µóóò=|©QÖ0¹Þ.’ÈfðýF¶jÑìÑ0Ôoš0œ¹ßÚè/+ôëâ×Å?qb•endstream endobj 5 0 obj 1898 endobj 3 0 obj << /Type /Page /MediaBox [0 0 612 792] /Parent 2 0 R /Resources << /ProcSet [/PDF /Text] /Font << /R10 10 0 R /R8 8 0 R /R7 7 0 R /R6 6 0 R >> >> /Contents 4 0 R >> endobj 13 0 obj <> stream xœXÛnÛF}×W, usÃå}óæØNš6ŽKASÀ@ASkiŠ”—¤Tõü+ùÇÎÞx“ä´…ìÃÙ93gæÌÆÅ¹òÇüÎV“ÇÉ#"ê™ý•­Ð›ÙäÕm$Ì&Ž‹?@³í„ GÙ¡ØCqV'Ó«3tw‚t÷òåìëÄUf‰‹}‚ål~2ÝU5[¡«´HLü,<¢Y6‰]ìE4ÑfÕ•ù<›Ÿâ0Š•§{Æ -š4Gpœ´#8Š"ik΋±ùÚîî$Ñ¡¼ºM åÕ <‚ýÀCNH»ï\Y”¾}@©|¼/²¼™3T/:›ž¿[—¢Fi…~™]}@Y¹Z±¢ä‚=6\° 9[T ä\£e½Êï^âaŽqï}xqüð‹emO”!Ô|ÅМWµà÷ =‰pl¬›š—Åø0ºØ»ÓJýž¸Æ€˜œ>𜠄ë0=ùþFðB‡ÐâyŠ}œÄ´ç€ÉZëœ>(X •v Q𠦥ÚdÃZP¨;µÏ‹S´Ö‘”¨ªçeSïÆÑàëc€K±Jëaˆm,CìoËŽ.ˆv ?>!ŽC:8n”’ °)¹)«Šßç m¤Eàâ0±Ó¼NÁ÷#÷~Œ=×Bã'Ö{*„—q~ª(‰Òb޲¼\ŒsçÅ1öÝ.wëãÔÔ|È!$ù³²xZ4"• <^šñ«ãÞ§2¡÷;T‹´¨˜¨0º`Ò> 1MlRÓ&¯¯¤eѬî™@åZ±ª‚ùRíƒPì{ÝñõbldŸk…³ùצҥ‡0QÀ0Z¦ÕÕ©¬`Åÿf *I™„ÿ¡ž‚èúG–³ÏOÑ=_¨r.›Û+g-I;Ä?œ4º·Ò¢7š#G± k·í:!À‘gã)x±8žx7ÁQ¯îù‘ÄC ŸKûǶÂj–kT±bÜPøËøš+(J¯-[âx~ˆ£o ›Ç)‹(vIë¸Hÿ;VÁòt÷ï"VÑ!Žc“uƒ2žtSÁ@÷л®ß"Øü¨‡«RJ SrR·³¶Y,dYy¡‡‹lmø ±4[¢u**6G9/öXG}L|?iØ™±ýHF¶mƒý«D×[—q¨¿q ½á«ß.ÿø]Z€¢„­¢\ß^LÇÄT¯C[´j•C…¥pÀVá¹8öMå£î T È•¬ö·¢éÄ“ºf:…í¬A§l±~µí¥ÀÃÄ| æŽ*` è}—9$ \èž¿ |rÁ!ØSKSá4H[ŸmPÚžÑ9„¶0!ð\ °=„‡P¹ApU°‡Jž¨7¹><Ý -FeàG@t 0òÚÒ \˜MŠâªn9d¸xÏòÒÄ©@D´©ÚŽhjAcb¸úfq^æ{ƒ90•¿}÷fD娆0eµÞ OïÓìÛB”ÔYéq9 a„ÝÎñh1ð";ëÏa½”’†Êµ¬Éë!èw‡ÆÕwÕÆŽObØ=¢D’±³ù¶Óq ‰©”\)‹Å`à÷2!Šóè^9E©öza`öï¯jTZ˜ ÏÓŠMôRÍ7ìH‡´ú!Ò´û”ƒ4£ œÊ©+½¶’;„Òox­èëóÈ5+¾ézÒCd;GúýPã­Ð7ðÃCôí!RÈ=/&V[Ùh!’ƒÃµ'í ‘Ýb)J|$)}³%è…¦P…ìee¯+¶ M&&=Ÿ§—Þ^¾»ür3¢†0)MlÊá´†ß\PØSÁÝF`w¶Õ†õómoimÙÜä£AŽZÎaêé™6ÜÒk)cÚŸR°sXßÊúPªvkù°8VĦáÐ~-Óó TÓÒ©¯¥˜ó";”-S‘fµUþMw==´‹¡àeSéþ…»CR‹±V áPjïÒ¥Ó:~?6¬È8m»ä ÎrA„I”§ÌÅ-¯—H_i„íXmx^;°wlŒPF­ìCRdGCzr=T#®ÕvíÞV£äø nضò‹Ï£{Ž)†"úùãû/š)ý¼`É‹‹çÉÏÑOJì£{ÄF°m ä»È#¯ú&-¡Ôÿio3°çµ‡í¶c©è-Ä À‰ysúÐr/»¥¶[—ô¯GíåDÑ@o^¬Ÿ¸*‹zy*ôÒËÏÕ³ê¥` 嬖,¹, ”Ë㾊#¾xÑÔìøgÕáÏ*­0Wl&Àb'ÖJ4½@—­™àò?MÒ\Ó’b^_gu)Wg/9Ežë•x`_O>¹œ¡O“O“o-ëaendstream endobj 14 0 obj 1745 endobj 12 0 obj << /Type /Page /MediaBox [0 0 612 792] /Parent 2 0 R /Resources << /ProcSet [/PDF /Text] /Font << /R10 10 0 R /R8 8 0 R /R7 7 0 R /R6 6 0 R >> >> /Contents 13 0 R >> endobj 16 0 obj <> stream xœÍX_oÛ6÷§àŠ&@̈¤DJú°&éÚ£iì`  eÆÑ*Kž$'q?C¿Ê¾ãŽ”(Û”äÛ , `Dº;ÞŸßýîhäéßæ3^þý‰ˆyf?â5z3]Þqý`v?{8d>š=9$(>©õ—rw¬=†7cRë<ôë<äÛbXéÝRYer­†¿ô+–É…’ -v•*‡µïûµU¦ŸCM‰)B„=E¢~÷¨Ú"Døöyšo*U¶Tn˜A„¢öÐê?>´Pq²ITV}ãÜ·ýç*•»~Ï25;¥<äÁþt N•¬¶%tA¯µÕ<TQä… ÑCs/úͽDzqu"”ù<ëWÎL’#Löù}J“Ì_ŠöƪYÉ*«|sÂù|»Ù*Uh!ãÏe*ËÇDH­‰«4_M!g²´éGâ5R¢a„G™nÕñ1c&ÀÕoßß;j|Eþ .Ó´d^&%”«B²t,0†¹ 3B;Û{V¿a5êY3›=¥y ¤’¬B9„dð€Öª,5F°¼Fd~ެŸc!ÚÌäëu ÇÖ7ßòhg¬œ¬´I™BX…ÚäE…”„¦è·²èÈvjéÛµ+2["$”oª$Ï^ûù˜ˆ ±öוaÊ f„Ûx®Õb»r3ÍËüÿ ¼T ý‚y˜Skm»ZA&¶ïób-u¦P•CA L;Ó„´.⫽mÃúé7ó “0ðÚ|?š|³ˆà@6ß7Ùr–رÓÁÏRVNÚ&<Òcv£Û"ºz‹]éäU iR¼P«{N3° C²?wŽ4ã_׃‡Mg`ºNÊÍA}–…À~‹Þn,T`.,Ž3G`gi°ó;ü\N&—××ã:PÉÈ ý»w¯&“WÓ©ãtÀÿi[\›S”‰ ¾/Ó£Ò#ðV&E§GG³íza§AÛì>;ìv]Z¬ÉÀnƒœy¬qÑïÇíL·oŠýÐ"½>Íå0 «œpc»³³õm’¶c­µJ|˜Ó<,xhPI¼£€Ð *h€½PD[#'ôU»ÖÙŽ _=Ûœýd ,·G[ÊjaYQ³¸–k9"%`#l©+Î×›$UKô”Tέ{€`_°Fþ×éͧ»›_n~»=6ÎÙÞæ…[N8˜Ûrö%t µ@,MÆõÊÏMAXÈ0!m»,t2­D½ÕCÜAÃð«m* dÞCs f­>o `M“Ûr—UòxõkaÃê[¨O5ÌÏÌKô€]<%¥2‡Yš-e±DWЂ‹B?Ýo³X÷a{Gû@m½„0áo~6?×Ôµ-Õ£÷uÃ|…7¨Ý½À§~=‘­ð`î¼üéåE)ø¯NL VN1eßÚ‹ í›Ó]̃™¼_‡;ýå‚—S "~ ƒ´}ÕC#܈öÒÈ¿_=ÒšÉÃ! ܬ9Q—uê¤ø«ÕÓÀm:øÞlª’i™§‚8ð­''É÷àÎOêÝ£Ýv>F ïvOz27rŠISÿ¼èâ3‚:éO»nÄO@3~4ë*ôà¸RßW$.¹>¶¸|›çP‘™zv·|~ Œ4èYó艹^ qÈ{Aµ¿vO‡bï“æ[wk¤§&4e¬žÐnÍòmµÙVv›­P ⟭í}ÁhSŸÛÆÆî˜fùø†Ô¾ÒW(oÿN ,Mi`%Ë8I:·ÁØÐÀ¤Œzö{j:['\߀ ì÷XK—b¢Id +uO˜Ôx¨= ]˜Ì4F `z,LºßL¯ÑÍóF‰¾0Jã&~Öq•ëæ¡á¢žGÌ´‡A#Àô“›ú8ú8ú¾¾4nendstream endobj 17 0 obj 1565 endobj 15 0 obj << /Type /Page /MediaBox [0 0 612 792] /Parent 2 0 R /Resources << /ProcSet [/PDF /Text] /Font << /R10 10 0 R /R8 8 0 R /R6 6 0 R >> >> /Contents 16 0 R >> endobj 19 0 obj <> stream xœµXKrÛ8ÝëØÅ©² @pvNâ‰]å_,Î.Z‚lÆ©”Ïr•Üq ñ'Å™š)/T&F÷Ã{ýa€ ôŸý¯'ß&ß1ÏÜÏ|Þ'“w·B?H–“i€% QòWyxH<’Ä@Šm×´rÀ\憞%ÇAG#î9ã!ÇÌ}eä±zi8¢X„Eät|Öâ‡äÂðèälƒÓ,®Ódž½v™ 8àÄ"¥r´,ª«âý€TrŒŠÒºË r"™õþ8ë,€<ÅxlQËç#nm}ÞL+`ÑÍT¾˜îØÉ xÉ=;×i¶BË¢DWI«„¿©éÑÀcK$‹¾ ÿ&Ó²Ì-:…ήgÉU‹ö$”˜Z¸N.O‡Ô–ÒøZþ›{™2!1¸ãÚy>_mꤚgY‘½ˆ'­è>ݘd >kÉÄx2ûp~ît‘Vè,¹¼0ºWy=LØÖ¥1Ž{]ÂæÔÅõâªL+çJI-ÙÊ~Ê%r©Kõƒ„ åÖ¸¢M{€YœÛä `ù\0r k¾»ƒðT°æ™½ëmý'ð¡çghÁ_úW>ùxÄo@«Ä=Òý+žDqËT/`F]•ï9JbqkëgaB¡!Áœûdz“Íëm©N.’—LÏ—½#1Å Øÿëö¢»_ø £=-Ž¡ôÔèä¢%Qcá%š4¥ºHó8Á¼šÔ÷Ö®ڷؽ©³–°á°ó*³´?¿üd¨>­Óûáe(÷áÁ2À¨Öf܃ó"Ëû÷JàÉÈçºÉÔLèj<˜ªö°€~IìJ à±iŽÐxõ Ö´Å6”Ä&u²47Ð_¬4†¬y!ý?ŒK‹L+ºTM…÷n„ ‘ÄR ˜Æ -Ú Øû2ÖÀK¨¥´ßO»ú«1=YUl˹B`bO è&áÀI¼iu^¶ÐäMÖoRFI››JX“¢-üS¢•ZÖ Ãâ ñZOa"ëó¢ÌaTh­´ cjµ2p¹Æcà0ì^dŸ-Þÿ„„£CRþ°˜uìøüæ Áa?s}Ä`^бìy²“tkH%ÍÀŽë”cÃ~T-u‘]2z1]:40„¸GE¹¨ú$ªšÑƱHWŒO €LWçùr Â€î-ùSA†uÇšBÚô…šû „¹ù…Ëuwß-øÔ ‹­=uZÊȧc%Þu“ƒ¥›î†¹AŠñ. ³:­·ƒÒéš„íúN•{S¬k²›eŽžu±A•±ŠÖªª€¬c)@êíS)@÷¢ãëívÐ*ˆà€§$þµ§%جÌóµ¹»Qg¹oI÷9+0åg“l0Ä8gG›ÊÈŽ0ñiIÓ*6+B†cǺþ˜ézçÖ³ˆ·ˆ°}5ýfüóŸ€÷¢Ð#²—¨pœìïE¹ úTmÃAlVõ6õ¢ðvyã—½h>Ö‹ÞªUúr“fƒz*ÄŽu§á=Ó–u,A¾³Ñ¢ëQù É c¬ãî­šg›  è¢k5À˜j=eoŽ×>–ÎLõØ> >> /Contents 19 0 R >> endobj 22 0 obj <> stream xœWÛnÛ8}÷WðmS bDêB©X,¶i’&E¼mcõa E¢Õ’èJt³þ‡üJÿq‡7Ù–ÝÈ…ÍÌ™9s8ò1A¾ú¶¿‹fòmò }æ~ :Ï&gw±:ÈæÏÇI¢ìqB§í£ˆ…pԜ̦oЗ” /¯^e_'¾6K|¤XfåÉlÓKÞ iÞæ Þý¦Œ(ŽPVL˜iœ&ƬŸÚÇ‹ RÅL{Š0µy»Îká”Áq+[a?ŒÝ—“dH¥˜xAB±ï'È  —¨ãu¾A=oKÞ¡§ZÂϼWOœÝßbN%)³¹É®jؘ¸ª„!v9GyÝ óyb?"…ijL.Ûï¼+~Ç‹jUñV^U*î¾GOuEá}çzÉ$)&Iš†æ|ó¨«@1¡æ@t%ÞÈ #ä üNžiÌc¬ÌV¸]7÷9 î;H@]Q?о¯îk޾ëbYÐ49å „¢ãGç#ÁРôyMRј“½±ÖXBË.oûùÒ¸l¢x'áŸ÷ÅŽ‚C™®Œ?tͼê»ÈµgÓ×b‘åã9í1WɳâóqwšU>=z¬äêµ[$ü’€a§ß?¹¦~•~·†~„Ôlñɼ“YÕŒ;çð•¹ñ®jJtýa*L ÝÆ®ŒV)æ7ŸWä>CK0£é6"> i•–PKˆ ÏE×äÒJâ1Ç,Å4p„?„B“á¾­úýÒ ³Äêoø:›NÏ..úæzôh* ¶ý|óyguÇîvή?ÜÆ2†j:Ìïón¹Üy€5#î‘íztZwËu » oÑï_åŸË:_Z”,uC˱¡<¼8øÖÙâzÍöH õ!Åù f~7"*` äY®n÷irÛÙÐAÊ•¸mxÞ¡y'Ô­[Í u¢lÍÞ§äÖRßìÔ‡¨—0ë{¹ÍÔÞÌ&™Â-kþìQ+䃦â½XÛÝï¸Láåj¸h7[§!¨«M’ÕWi¥¨Þ# šÒl ›Ùo<š‚´Åê—é´X7 êv:üUÁ£9<©µ÷>/AôuÕ?jø)ÓñÎgèòßï*í¡Ö5LaësÛî‡B õöA“SD}Ÿh8°o&‘5ˆÔÉe†>M>Mþ]8âWendstream endobj 23 0 obj 1467 endobj 21 0 obj << /Type /Page /MediaBox [0 0 612 792] /Parent 2 0 R /Resources << /ProcSet [/PDF /Text] /Font << /R10 10 0 R /R8 8 0 R /R7 7 0 R /R6 6 0 R >> >> /Contents 22 0 R >> endobj 10 0 obj <> endobj 8 0 obj <> endobj 11 0 obj <> endobj 7 0 obj <> endobj 6 0 obj <> endobj 9 0 obj <> endobj 2 0 obj << /Type /Pages /Kids [ 3 0 R 12 0 R 15 0 R 18 0 R 21 0 R ] /Count 5 >> endobj 1 0 obj << /Type /Catalog /Pages 2 0 R >> endobj 24 0 obj << /CreationDate (D:20020913083450) /Producer (GNU Ghostscript 5.50) >> endobj xref 0 25 0000000000 65535 f 0000010438 00000 n 0000010351 00000 n 0000002003 00000 n 0000000015 00000 n 0000001983 00000 n 0000010198 00000 n 0000010126 00000 n 0000009977 00000 n 0000010286 00000 n 0000009898 00000 n 0000010067 00000 n 0000004021 00000 n 0000002183 00000 n 0000004000 00000 n 0000005861 00000 n 0000004203 00000 n 0000005840 00000 n 0000007984 00000 n 0000006033 00000 n 0000007963 00000 n 0000009716 00000 n 0000008156 00000 n 0000009695 00000 n 0000010487 00000 n trailer << /Size 25 /Root 1 0 R /Info 24 0 R >> startxref 10575 %%EOF sma-1.4.orig/docs/sma.ps0000644000175000017500000005231207603333514015352 0ustar apollockapollock%!PS-Adobe-3.0 %%Creator: groff version 1.15 %%CreationDate: Fri Sep 13 08:34:33 2002 %%DocumentNeededResources: font Times-Roman %%+ font Times-Bold %%+ font Courier-Bold %%+ font Courier-Oblique %%DocumentSuppliedResources: procset grops 1.15 0 %%Pages: 5 %%PageOrder: Ascend %%Orientation: Portrait %%EndComments %%BeginProlog %%BeginResource: procset grops 1.15 0 /setpacking where{ pop currentpacking true setpacking }if /grops 120 dict dup begin /SC 32 def /A/show load def /B{0 SC 3 -1 roll widthshow}bind def /C{0 exch ashow}bind def /D{0 exch 0 SC 5 2 roll awidthshow}bind def /E{0 rmoveto show}bind def /F{0 rmoveto 0 SC 3 -1 roll widthshow}bind def /G{0 rmoveto 0 exch ashow}bind def /H{0 rmoveto 0 exch 0 SC 5 2 roll awidthshow}bind def /I{0 exch rmoveto show}bind def /J{0 exch rmoveto 0 SC 3 -1 roll widthshow}bind def /K{0 exch rmoveto 0 exch ashow}bind def /L{0 exch rmoveto 0 exch 0 SC 5 2 roll awidthshow}bind def /M{rmoveto show}bind def /N{rmoveto 0 SC 3 -1 roll widthshow}bind def /O{rmoveto 0 exch ashow}bind def /P{rmoveto 0 exch 0 SC 5 2 roll awidthshow}bind def /Q{moveto show}bind def /R{moveto 0 SC 3 -1 roll widthshow}bind def /S{moveto 0 exch ashow}bind def /T{moveto 0 exch 0 SC 5 2 roll awidthshow}bind def /SF{ findfont exch [exch dup 0 exch 0 exch neg 0 0]makefont dup setfont [exch/setfont cvx]cvx bind def }bind def /MF{ findfont [5 2 roll 0 3 1 roll neg 0 0]makefont dup setfont [exch/setfont cvx]cvx bind def }bind def /level0 0 def /RES 0 def /PL 0 def /LS 0 def /MANUAL{ statusdict begin/manualfeed true store end }bind def /PLG{ gsave newpath clippath pathbbox grestore exch pop add exch pop }bind def /BP{ /level0 save def 1 setlinecap 1 setlinejoin 72 RES div dup scale LS{ 90 rotate }{ 0 PL translate }ifelse 1 -1 scale }bind def /EP{ level0 restore showpage }bind def /DA{ newpath arcn stroke }bind def /SN{ transform .25 sub exch .25 sub exch round .25 add exch round .25 add exch itransform }bind def /DL{ SN moveto SN lineto stroke }bind def /DC{ newpath 0 360 arc closepath }bind def /TM matrix def /DE{ TM currentmatrix pop translate scale newpath 0 0 .5 0 360 arc closepath TM setmatrix }bind def /RC/rcurveto load def /RL/rlineto load def /ST/stroke load def /MT/moveto load def /CL/closepath load def /FL{ currentgray exch setgray fill setgray }bind def /BL/fill load def /LW/setlinewidth load def /RE{ findfont dup maxlength 1 index/FontName known not{1 add}if dict begin { 1 index/FID ne{def}{pop pop}ifelse }forall /Encoding exch def dup/FontName exch def currentdict end definefont pop }bind def /DEFS 0 def /EBEGIN{ moveto DEFS begin }bind def /EEND/end load def /CNT 0 def /level1 0 def /PBEGIN{ /level1 save def translate div 3 1 roll div exch scale neg exch neg exch translate 0 setgray 0 setlinecap 1 setlinewidth 0 setlinejoin 10 setmiterlimit []0 setdash /setstrokeadjust where{ pop false setstrokeadjust }if /setoverprint where{ pop false setoverprint }if newpath /CNT countdictstack def userdict begin /showpage{}def }bind def /PEND{ clear countdictstack CNT sub{end}repeat level1 restore }bind def end def /setpacking where{ pop setpacking }if %%EndResource %%IncludeResource: font Times-Roman %%IncludeResource: font Times-Bold %%IncludeResource: font Courier-Bold %%IncludeResource: font Courier-Oblique grops begin/DEFS 1 dict def DEFS begin/u{.001 mul}bind def end/RES 72 def/PL 792 def/LS false def/ENC0[/asciicircum/asciitilde/Scaron/Zcaron /scaron/zcaron/Ydieresis/trademark/quotesingle/.notdef/.notdef/.notdef /.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef /.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef /.notdef/.notdef/space/exclam/quotedbl/numbersign/dollar/percent /ampersand/quoteright/parenleft/parenright/asterisk/plus/comma/hyphen /period/slash/zero/one/two/three/four/five/six/seven/eight/nine/colon /semicolon/less/equal/greater/question/at/A/B/C/D/E/F/G/H/I/J/K/L/M/N/O /P/Q/R/S/T/U/V/W/X/Y/Z/bracketleft/backslash/bracketright/circumflex /underscore/quoteleft/a/b/c/d/e/f/g/h/i/j/k/l/m/n/o/p/q/r/s/t/u/v/w/x/y /z/braceleft/bar/braceright/tilde/.notdef/quotesinglbase/guillemotleft /guillemotright/bullet/florin/fraction/perthousand/dagger/daggerdbl /endash/emdash/ff/fi/fl/ffi/ffl/dotlessi/dotlessj/grave/hungarumlaut /dotaccent/breve/caron/ring/ogonek/quotedblleft/quotedblright/oe/lslash /quotedblbase/OE/Lslash/.notdef/exclamdown/cent/sterling/currency/yen /brokenbar/section/dieresis/copyright/ordfeminine/guilsinglleft /logicalnot/minus/registered/macron/degree/plusminus/twosuperior /threesuperior/acute/mu/paragraph/periodcentered/cedilla/onesuperior /ordmasculine/guilsinglright/onequarter/onehalf/threequarters /questiondown/Agrave/Aacute/Acircumflex/Atilde/Adieresis/Aring/AE /Ccedilla/Egrave/Eacute/Ecircumflex/Edieresis/Igrave/Iacute/Icircumflex /Idieresis/Eth/Ntilde/Ograve/Oacute/Ocircumflex/Otilde/Odieresis /multiply/Oslash/Ugrave/Uacute/Ucircumflex/Udieresis/Yacute/Thorn /germandbls/agrave/aacute/acircumflex/atilde/adieresis/aring/ae/ccedilla /egrave/eacute/ecircumflex/edieresis/igrave/iacute/icircumflex/idieresis /eth/ntilde/ograve/oacute/ocircumflex/otilde/odieresis/divide/oslash /ugrave/uacute/ucircumflex/udieresis/yacute/thorn/ydieresis]def /Courier-Oblique@0 ENC0/Courier-Oblique RE/Courier-Bold@0 ENC0 /Courier-Bold RE/Times-Bold@0 ENC0/Times-Bold RE/Times-Roman@0 ENC0 /Times-Roman RE %%EndProlog %%Page: 1 1 %%BeginPageSetup BP %%EndPageSetup /F0 10/Times-Roman@0 SF -.834(SMA \( 8 \))72 48 R(System Manager') 142.067 E 2.5(sM)-.55 G 139.567(anual SMA)-2.5 F 1.666(\(8\))1.666 G/F1 10/Times-Bold@0 SF -.2(NA)72 108 S(ME).2 E/F2 10/Courier-Bold@0 SF(sma) 102 120 Q F0 2.52.5 G(endmail Log Analyser)-2.5 E F1(SYNOPSIS)72 144 Q F2(sma)102 156 Q F0([)3.333 E F2(OPTIONS).833 E F0 3.333(][).833 G /F3 10/Courier-Oblique@0 SF(file ...)-2.5 E F0(]).833 E F1(DESCRIPTION) 72 180 Q F0(The)102 192 Q F2(sma)2.755 E F0 .255(utility analyses sendm\ ail log entries and produces a summary of mail acti)2.755 F(vity)-.25 E (.)-.65 E F2(sma)5.254 E F0 .254(reads the input)2.754 F(from)102 204 Q F3(file)2.5 E F0(or from standard input and writes the report to standa\ rd output or \214le.)2.5 E F2(sma)102 222 Q F0 .227(can be con\214gured\ using command line options or con\214guration \214le, or both.)2.726 F .227(Command line options al-)5.227 F -.1(wa)102 234 S(ys o).1 E -.15 (ve)-.15 G(rride the con\214guration \214le.).15 E(The a)102 252 Q -.25 (va)-.2 G(ilable command line options are as follo).25 E(ws:)-.25 E F2 103.666 270 Q F0 -.15(Fo)21.334 G(rmat the report as ASCII.).15 E F2103.666 288 Q F3(color)6 E F0 (Set the background color of the HTML report as)137 300 Q F3(color.)2.5 E F2103.666 318 Q F3(string)6 E F0(Set report header as)137 330 Q F3(string.)2.5 E F2103.666 348 Q F3(date1,date2)6 E F0 .503 (Process log entry only if the date is between)137 360 R F3(date1)3.003 E F0(and)3.003 E F3(date2.)3.003 E F0 .503 (The format of the date is as fol-)3.003 F(lo)137 372 Q(ws: [[[[[[)-.25 E F3(cc)A F0(])A F3(yy)A F0(])A F3(mm)A F0(])A F3(dd)A F0(])A F3(HH)A F0 (])A F3(MM)A F0([).833 E F3(.SS).833 E F0 -1.666 .833(]] w)D(here)-.833 E F3(yy)167 390 Q F0 -1(Ye)23 G 1.232(ar in abbre)1 F 1.232 (viated form \(for years 1969-2068\).)-.25 F 1.232(The format)6.232 F F3 (ccyymmddHHMM)3.732 E F0(is)3.732 E (also permitted, for non-ambiguous years.)202 402 Q F3(mm)167 414 Q F0 (Numeric month, a number from 1 to 12.)23 E F3(dd)167 426 Q F0(Day)23 E 2.5(,an)-.65 G(umber from 1 to 31.)-2.5 E F3(HH)167 438 Q F0(Hour)23 E 2.5(,an)-.4 G(umber from 0 to 23.)-2.5 E F3(MM)167 450 Q F0 (Minute, a number from 0 to 59.)23 E F3(SS)167 462 Q F0 (Second, a number from 0 to 61 \(59 plus a maximum of tw)23 E 2.5(ol)-.1 G(eap seconds\).)-2.5 E(Ev)137 480 Q 1.884(erything b)-.15 F 1.883(ut t\ he minute is optional. The dates must be separated using a colon, witho\ ut an)-.2 F(y)-.15 E(whitespace characters. If either of the dates is m\ issing, current date is used.)137 492 Q F2103.666 510 Q F0 (Print the cop)21.334 E(yright notice and e)-.1 E(xit.)-.15 E F2 103.666 528 Q F0(Process only the domain portion of email address.) 21.334 E F2103.666 546 Q F3(file)6 E F0 .883 (Read the con\214guration from)137 558 R F3(file)3.383 E F0 .883 (instead of the def)3.383 F .883(ault con\214guration \214le. The def) -.1 F .884(ault con\214gura-)-.1 F(tion \214le is de\214ned in conf.h.) 137 570 Q F2103.666 588 Q F0(Do not use def)21.334 E (ault con\214guration \214le e)-.1 E -.15(ve)-.25 G 2.5(ni).15 G 2.5(fi) -2.5 G 2.5(te)-2.5 G(xists.)-2.65 E F2103.666 606 Q F3(name)6 E F0 (Use)137 618 Q F3(name)2.5 E F0(as hostname.)2.5 E F2103.666 636 Q F3(string)6 E F0(Process only lines with syslog tag)137 648 Q F3(string) 2.5 E F2103.666 666 Q F0(Print help message and e)21.334 E(xit.) -.15 E(BSD Experimental)72 750 Q(October 28, 2001)123.315 E(1)194.145 E EP %%Page: 2 2 %%BeginPageSetup BP %%EndPageSetup /F0 10/Times-Roman@0 SF -.834(SMA \( 8 \))72 48 R(System Manager') 142.067 E 2.5(sM)-.55 G 139.567(anual SMA)-2.5 F 1.666(\(8\))1.666 G/F1 10/Courier-Bold@0 SF103.666 96 Q F0 (Include the ASCII report as HTML comment \(requires -w or -O html\).) 21.334 E F1103.666 114 Q F0(Do not report the time distrib)21.334 E(ution.)-.2 E F1103.666 132 Q/F2 10/Courier-Oblique@0 SF(file)6 E F0(Print the report as)137 144 Q F2(file.)2.5 E F0(If not gi)2.5 E -.15 (ve)-.25 G(n, print to stdout.).15 E F1103.666 162 Q F2(format)6 E F0 -.15(Fo)137 174 S(rmat the report as).15 E F2(format.)2.5 E F0 (Possible v)2.5 E(alues for)-.25 E F2(format)2.5 E F0 (are ascii, html and clog.)2.5 E F1103.666 192 Q F0 (Print current con\214guration to stdout.)21.334 E F1103.666 210 Q F0(Sort by transfers. Def)21.334 E(ault is by number of messages.)-.1 E F1103.666 228 Q F2(value)6 E F0 (Adjust the internal hash table size. Possible v)137 240 Q(alues for) -.25 E F2(value)2.5 E F0(are normal, big and huge.)2.5 E F1103.666 258 Q F0(Do not print an)21.334 E 2.5(yw)-.15 G(arning messages.)-2.6 E F1103.666 276 Q F2(num)6 E F0 (Number of the top senders and recipients in the report. Def)137 288 Q (ault is 10.)-.1 E F1103.666 306 Q F2(num)6 E F0 (Number of the top relay senders and recipients in the report.)137 318 Q (Def)5 E(ault is 5.)-.1 E F1103.666 336 Q F0(Print some deb)21.334 E(ugging information for each parsed line.)-.2 E F1103.666 354 Q F0 -.15(Fo)21.334 G(rmat the report as HTML.).15 E/F3 10/Times-Bold@0 SF (KEYW)72 378 Q(ORDS)-.1 E F1(sma)102 390 Q F0 .238 (con\214guration \214le consists of k)2.738 F -.15(ey)-.1 G -.1(wo).15 G (rd-v).1 E .238(alue pairs.)-.25 F -1.27 -.74(Av a)5.238 H .238 (ilable con\214guration \214le k).74 F -.15(ey)-.1 G -.1(wo).15 G .237 (rds and v).1 F .237(alues are)-.25 F(listed belo)102 402 Q -.65(w.)-.25 G F1(BgColor)102 420 Q F2(RGB)6 E F0 (Set HTML report background color as)143 432 Q F2(RGB.)2.5 E F0 (Command line option:)2.5 E F14.166 E(BounceAddress)102 450 Q F2 (string)6 E F0(Set error message bounce address as)143 462 Q F2(string.) 2.5 E F1(CaseSensitive)102 480 Q F2(value)6 E F0 1.406 (Set \214lter case sensiti)143 492 R(vity)-.25 E 3.906(.P)-.65 G 1.406 (ossible v)-3.906 F 1.406(alues are)-.25 F F2(yes)3.906 E F0(or)3.906 E F2(no.)3.906 E F0 1.406(This options requires)3.906 F F1(USE_REGEXP) 3.907 E F0(compile time de\214nition.)143 504 Q F1(ClogFormat)102 522 Q F2(string)6 E F0 -.15(Fo)143 534 S 1.278 (rmatting string for Custom Log format.).15 F F2(format)6.278 E F0 1.277 (consists of ordinary characters and v)3.777 F(arious)-.25 E(tw)143 546 Q(o-character sequencies which are replaced with b)-.1 E(uilt-in v)-.2 E (ariables as follo)-.25 E(ws:)-.25 E F1(%U)143 564 Q F0 (time in UNIX time format)29 E F1(%D)143 582 Q F0(time in form "W)29 E (ed Jun 30 21:49:08 1993")-.8 E F1(%y)143 600 Q F0(year)29 E 2.5(,f)-.4 G(our digits)-2.5 E F1(%m)143 618 Q F0(month, in digits)29 E F1(%M)143 636 Q F0(month, three letter English)29 E F1(%n)143 654 Q F0(minute)29 E F1(%s)143 672 Q F0(second)29 E(BSD Experimental)72 750 Q (October 28, 2001)123.315 E(2)194.145 E EP %%Page: 3 3 %%BeginPageSetup BP %%EndPageSetup /F0 10/Times-Roman@0 SF -.834(SMA \( 8 \))72 48 R(System Manager') 142.067 E 2.5(sM)-.55 G 139.567(anual SMA)-2.5 F 1.666(\(8\))1.666 G/F1 10/Courier-Bold@0 SF(%d)143 96 Q F0(day)29 E F1(%h)143 114 Q F0(hour)29 E F1(%H)143 132 Q F0(hostname)29 E F1(%z)143 150 Q F0(size in bytes)29 E F1(%f)143 168 Q F0(en)29 E -.15(ve)-.4 G(lope sender).15 E F1(%t)143 186 Q F0(en)29 E -.15(ve)-.4 G(lope recipient).15 E F1(%F)143 204 Q F0 (relay sender)29 E F1(%T)143 222 Q F0(relay recipient)29 E F1(%S)143 240 Q F0(status \(1 = sent, 0 = error\))29 E F1(%%)143 258 Q F0(%-character) 29 E F1(\\n)143 276 Q F0(ne)29 E(wline)-.25 E F1(\\t)143 294 Q F0 (tab stop)29 E F1(\\\\)143 312 Q F0(single backslash)29 E F1 (ClogSentOnly)102 330 Q/F2 10/Courier-Oblique@0 SF(value)6 E F0(If)143 342 Q F2(value)2.5 E F0(is set as)2.5 E F2(yes)2.5 E F0 2.5(,p)2.5 G (rint only sent messages \(status = 1\).)-2.5 E F1(Comment)102 360 Q F2 (string)6 E F0(Set report header as)143 372 Q F2(string.)2.5 E F0 (Command line option:)2.5 E F14.166 E(Debug)102 390 Q F2(value)6 E F0(If)143 402 Q F2(value)2.5 E F0(is set as)2.5 E F2(yes)2.5 E F0 2.5 (,p)2.5 G(rint deb)-2.5 E(ugging information to stderr)-.2 E 5(.C)-.55 G (ommand line option:)-5 E F14.166 E(EndTime)102 420 Q F2(date)6 E F0 1.169(Process log entry only if the date is before)143 432 R F2 (date.)3.669 E F0 1.17(The format of the)3.669 F F2(date)3.67 E F0(is) 3.67 E F1(YYYY/MM/DD-)3.67 E(HH:MM:SS.)143 444 Q F0 (Command line option:)2.5 E F14.166 E(EnvelopePairs)102 462 Q F2 (number)6 E F0(Set the number of the top en)143 474 Q -.15(ve)-.4 G (lope pairs as).15 E F2(number.)2.5 E F1(EnvelopeRecipientFilter)102 492 Q F2(string)6 E F0 .768(Set en)143 504 R -.15(ve)-.4 G .768 (lope recipient \214lter as).15 F F2(string.)3.268 E F0(If)3.268 E F1 (sma)3.268 E F0 .768(is compiled with)3.268 F F1(USE_REGEXP)3.268 E F0 (,)3.268 E F2(string)3.267 E F0(can)3.267 E .396(be re)143 516 R .397 (gular e)-.15 F .397(xpression of syntax de\214ned in re_format\(7\). O\ therwise the standard C library function)-.15 F (strstr\(\) is used. If the \214rst character of)143 528 Q F2(string)2.5 E F0(is '!', \214lter is re)2.5 E -.15(ve)-.25 G(rsed.).15 E F1 (EnvelopeRecipients)102 546 Q F2(number)6 E F0 (Set the number of the top en)143 558 Q -.15(ve)-.4 G (lope recipients as).15 E F2(number.)2.5 E F0(Command line option:)2.5 E F14.166 E(EnvelopeSenderFilter)102 576 Q F2(string)6 E F0(Set en) 143 588 Q -.15(ve)-.4 G(lope sender \214lter as).15 E F2(string.)2.5 E F0(See also)2.5 E F1(EnvelopeRecipientFilter)2.5 E F0 -.1(ke)2.5 G(yw) -.05 E(ord.)-.1 E F1(EnvelopeSenders)102 606 Q F2(number)6 E F0 (Set the number of the top en)143 618 Q -.15(ve)-.4 G(lope senders as) .15 E F2(number.)2.5 E F0(Command line option:)2.5 E F14.166 E (FooterText)102 636 Q F2(string)6 E F0(Set report footer as)143 648 Q F2 (string.)2.5 E F1(Format)102 666 Q F2(string)6 E F0 .233 (Set the output format as)143 678 R F2(string.)2.733 E F0 .233 (Possible v)2.733 F .233(alues are)-.25 F F2(ascii)2.733 E F0(,)2.733 E F2(html)2.732 E F0(and)2.732 E F2(clog.)2.732 E F0 .232(Command line) 2.732 F(BSD Experimental)72 750 Q(October 28, 2001)123.315 E(3)194.145 E EP %%Page: 4 4 %%BeginPageSetup BP %%EndPageSetup /F0 10/Times-Roman@0 SF -.834(SMA \( 8 \))72 48 R(System Manager') 142.067 E 2.5(sM)-.55 G 139.567(anual SMA)-2.5 F 1.666(\(8\))1.666 G (options:)143 96 Q/F1 10/Courier-Bold@0 SF4.166 E F0(,)2.5 E F1 4.166 E F0(and)2.5 E F14.166 E(HashTables)102 114 Q/F2 10 /Courier-Oblique@0 SF(string)6 E F0 .274 (Adjust the internal hash table size. Possible v)143 126 R .275 (alues are)-.25 F F2(normal)2.775 E F0(,)2.775 E F2(big)2.775 E F0(and) 2.775 E F2(huge.)2.775 E F0 .275(It is also possi-)2.775 F .517 (ble to specify a custom hash table size by de\214ning tw)143 138 R 3.017(ov)-.1 G .517(alues and separating them with a comma)-3.267 F(',) 143 150 Q 2.5('. Command)-.7 F(line option:)2.5 E F14.166 E (HeaderText)102 168 Q F2(string)6 E F0(Set report header as)143 180 Q F2 (string.)2.5 E F1(HostName)102 198 Q F2(string)6 E F0 .855 (Set the hostname as)143 210 R F2(string.)3.355 E F0(Normally)3.355 E 3.355(,H)-.65 G .856(ostName is tak)-3.355 F .856 (en from log \214les, or)-.1 F 3.356(,i)-.4 G 3.356(nc)-3.356 G .856 (ase of Send-)-3.356 F(mail for NT)143 222 Q 2.5(,f)-.74 G (rom the compile time de\214ne HOSTN)-2.5 E 2.5(AME. Command)-.35 F (line option:)2.5 E F14.166 E(IncludeAscii)102 240 Q F2(value)6 E F0 .383(Include the ASCII report as HTML comment. Possible v)143 252 R .383(alues are)-.25 F F2(yes)2.883 E F0(or)2.882 E F2(no.)2.882 E F0 .382(Command line op-)2.882 F(tion:)143 264 Q F14.166 E(OutFile) 102 282 Q F2(file)6 E F0(Print the report as)143 294 Q F2(file.)2.5 E F0 (Command line option:)2.5 E F14.166 E(PictureALT)102 312 Q F2 (string)6 E F0(If)143 324 Q F1(PictureURL)2.5 E F0(is de\214ned, set AL) 2.5 E 2.5(Tt)-.92 G -.15(ex)-2.5 G 2.5(ti).15 G (nside the IMG HTML-tag as)-2.5 E F2(string.)2.5 E F1(PictureLink)102 342 Q F2(string)6 E F0(If)143 354 Q F1(PictureURL)2.5 E F0 (is de\214ned, mak)2.5 E 2.5(et)-.1 G(he picture as link pointing to) -2.5 E F2(string.)2.5 E F1(PictureParameters)102 372 Q F2(string)6 E F0 (If)143 384 Q F1(PictureURL)2.5 E F0 (is de\214ned, set additional IMG parameters as)2.5 E F2(string.)2.5 E F1(PictureURL)102 402 Q F2(URL)6 E F0 1.024 (Include a picture with source URL as)143 414 R F2(URL)3.525 E F0 1.025 (in HTML report. The picture appears in a upper left)3.525 F 2.904 (corner of the page. See also)143 426 R F1(PictureParameters)5.404 E F0 (,)5.404 E F1(PictureALT)5.404 E F0(and)5.404 E F1(PictureLink)5.404 E F0 -.1(ke)143 438 S(yw)-.05 E(ords.)-.1 E F1(PrintGeneralInfo)102 456 Q F2(value)6 E F0 (Print the General Information section in report. Possible v)143 468 Q (alues are)-.25 E F2(yes)2.5 E F0(or)2.5 E F2(no.)2.5 E F1(PrintStatus) 102 486 Q F2(number)6 E F0(Set the number of the top status messages as) 143 498 Q F2(number.)2.5 E F1(PrintRule)102 516 Q F2(number)6 E F0 (Set the number of the top ruleset rejections as)143 528 Q F2(number.) 2.5 E F1(PrintTime)102 546 Q F2(value)6 E F0 .75(Print the T)143 558 R .75(ime Distrib)-.35 F .751(ution section in report. Possible v)-.2 F .751(alues are)-.25 F F2(yes)3.251 E F0(or)3.251 E F2(no.)3.251 E F0 .751(Command line op-)3.251 F(tion:)143 570 Q F14.166 E (RelayPairs)102 588 Q F2(number)6 E F0 (Set the number of the top relay address pairs as)143 600 Q F2(number.) 2.5 E F1(RelayRecipientFilter)102 618 Q F2(string)6 E F0 (Set relay recipient \214lter as)143 630 Q F2(string.)2.5 E F0(See also) 2.5 E F1(EnvelopeRecipientFilter)2.5 E F0 -.1(ke)2.5 G(yw)-.05 E(ord.) -.1 E F1(RelayRecipients)102 648 Q F2(number)6 E F0 (Set the number of the top relay recipients as)143 660 Q F2(number.)2.5 E F0(Command line option:)2.5 E F14.166 E(RelaySenderFilter)102 678 Q F2(string)6 E F0(BSD Experimental)72 750 Q(October 28, 2001) 123.315 E(4)194.145 E EP %%Page: 5 5 %%BeginPageSetup BP %%EndPageSetup /F0 10/Times-Roman@0 SF -.834(SMA \( 8 \))72 48 R(System Manager') 142.067 E 2.5(sM)-.55 G 139.567(anual SMA)-2.5 F 1.666(\(8\))1.666 G (Set relay sender \214lter as)143 96 Q/F1 10/Courier-Oblique@0 SF (string.)2.5 E F0(See also)2.5 E/F2 10/Courier-Bold@0 SF (EnvelopeRecipientFilter)2.5 E F0 -.1(ke)2.5 G(yw)-.05 E(ord.)-.1 E F2 (RelaySenders)102 114 Q F1(number)6 E F0 (Set the number of the top relay senders as)143 126 Q F1(number.)2.5 E F0(Command line option:)2.5 E F24.166 E(ShowUsers)102 144 Q F1 (value)6 E F0(If)143 156 Q F1(value)2.95 E F0 .45(is set as)2.95 F F1 (no)2.95 E F0 2.95(,p)2.95 G .449 (rocess only the domain portion of the email address.)-2.95 F .449 (Command line op-)5.449 F(tion:)143 168 Q F24.166 E(Silent)102 186 Q F1(value)6 E F0(If)143 198 Q F1(value)2.5 E F0(is set as)2.5 E F1(yes) 2.5 E F0 2.5(,d)2.5 G 2.5(on)-2.5 G(ot print error messages.)-2.5 E (Command line option:)5 E F24.166 E(Sorting)102 216 Q F1(value)6 E F0 .17(Set the sort order as)143 228 R F1(value.)2.67 E F0 .17 (Possible v)2.67 F .17(alues are)-.25 F F1(number)2.67 E F0(or)2.67 E F1 (transfer.)2.67 E F0 .17(Command line option:)2.67 F F2144.666 240 Q(SyslogTag)102 258 Q F1(string)6 E F0 (Process only lines with syslog tag)143 270 Q F1(string.)2.5 E F0 (Command line option:)2.5 E F24.166 E(StartTime)102 288 Q F1(date) 6 E F0 1.621(Process log entry only if the date is after)143 300 R F1 (date.)4.121 E F0 1.62(The format of the)4.121 F F1(date)4.12 E F0(is) 4.12 E F2(YYYY/MM/DD-)4.12 E(HH:MM:SS.)143 312 Q F0 (Command line option:)2.5 E F24.166 E(TbColor)102 330 Q F1(RGB)6 E F0(Set HTML report table corner color as)143 342 Q F1(RGB.)2.5 E/F3 10 /Times-Bold@0 SF(FILES)72 366 Q F2(sma)102 378 Q F0 .067 (can as an option use a con\214guration \214le. It')2.566 F 2.567(sd) -.55 G(ef)-2.567 E .067 (ault location can be con\214gured using a compile time de-)-.1 F (\214ne)102 390 Q F2(DEFAULT_CONF)2.5 E F0(in \214le conf.h. By def)2.5 E(ault, it is de\214ned as)-.1 E F2(./sma.conf)2.5 E F3 -.5(AU)72 414 S (THOR).5 E F0(Jarkk)102 426 Q 2.5(oT)-.1 G(urkulainen )-.18 E F3 -.1(BU)72 450 S(GS).1 E F2(sma)102 462 Q F0 (tak)2.5 E(es the year from runtime year)-.1 E 5(.I)-.55 G 2.5(tk)-5 G (no)-2.5 E(ws nothing about the ne)-.25 E 2.5(wy)-.25 G (ear transitions in log \214les.)-2.5 E (The documentation contains a lot of bad english.)102 480 Q (BSD Experimental)72 750 Q(October 28, 2001)123.315 E(5)194.145 E EP %%Trailer end %%EOF sma-1.4.orig/docs/sma.txt0000644000175000017500000002357207603333514015555 0ustar apollockapollock SMA(8) System Manager's Manual SMA(8) NAME sma - Sendmail Log Analyser SYNOPSIS sma [OPTIONS] [file ...] DESCRIPTION The sma utility analyses sendmail log entries and produces a summary of mail activity. sma reads the input from file or from standard input and writes the report to standard output or file. sma can be configured using command line options or configuration file, or both. Command line options always override the configuration file. The available command line options are as follows: -a Format the report as ASCII. -b color Set the background color of the HTML report as color. -C string Set report header as string. -D date1,date2 Process log entry only if the date is between date1 and date2. The format of the date is as follows: [[[[[[cc]yy]mm]dd]HH]MM[.SS]] where yy Year in abbreviated form (for years 1969-2068). The format ccyymmddHHMM is also permitted, for non- ambiguous years. mm Numeric month, a number from 1 to 12. dd Day, a number from 1 to 31. HH Hour, a number from 0 to 23. MM Minute, a number from 0 to 59. SS Second, a number from 0 to 61 (59 plus a maximum of two leap seconds). Everything but the minute is optional. The dates must be separat- ed using a colon, without any whitespace characters. If either of the dates is missing, current date is used. -c Print the copyright notice and exit. -d Process only the domain portion of email address. -f file Read the configuration from file instead of the default configu- ration file. The default configuration file is defined in conf.h. -F Do not use default configuration file even if it exists. -H name Use name as hostname. -L string Process only lines with syslog tag string -h Print help message and exit. -i Include the ASCII report as HTML comment (requires -w or -O html). -n Do not report the time distribution. -o file Print the report as file. If not given, print to stdout. -O format Format the report as format. Possible values for format are ascii, html and clog. -p Print current configuration to stdout. -s Sort by transfers. Default is by number of messages. -t value Adjust the internal hash table size. Possible values for value are normal, big and huge. -q Do not print any warning messages. -l num Number of the top senders and recipients in the report. Default is 10. -r num Number of the top relay senders and recipients in the report. Default is 5. -v Print some debugging information for each parsed line. -w Format the report as HTML. KEYWORDS sma configuration file consists of keyword-value pairs. Available con- figuration file keywords and values are listed below. BgColor RGB Set HTML report background color as RGB. Command line option: -b BounceAddress string Set error message bounce address as string. CaseSensitive value Set filter case sensitivity. Possible values are yes or no. This options requires USE REGEXP compile time definition. ClogFormat string Formatting string for Custom Log format. format consists of or- dinary characters and various two-character sequencies which are replaced with built-in variables as follows: %U time in UNIX time format %D time in form "Wed Jun 30 21:49:08 1993" %y year, four digits %m month, in digits %M month, three letter English %n minute %s second %d day %h hour %H hostname %z size in bytes %f envelope sender %t envelope recipient %F relay sender %T relay recipient %S status (1 = sent, 0 = error) %% %-character \n newline \t tab stop \\ single backslash ClogSentOnly value If value is set as yes , print only sent messages (status = 1). Comment string Set report header as string. Command line option: -C Debug value If value is set as yes , print debugging information to stderr. Command line option: -v EndTime date Process log entry only if the date is before date. The format of the date is YYYY/MM/DD-HH:MM:SS. Command line option: -D EnvelopePairs number Set the number of the top envelope pairs as number. EnvelopeRecipientFilter string Set envelope recipient filter as string. If sma is compiled with USE REGEXP , string can be regular expression of syntax defined in re format(7). Otherwise the standard C library function strstr() is used. If the first character of string is '!', filter is reversed. EnvelopeRecipients number Set the number of the top envelope recipients as number. Command line option: -l EnvelopeSenderFilter string Set envelope sender filter as string. See also EnvelopeRecipientFilter keyword. EnvelopeSenders number Set the number of the top envelope senders as number. Command line option: -l FooterText string Set report footer as string. Format string Set the output format as string. Possible values are ascii , html and clog. Command line options: -a , -w and -O HashTables string Adjust the internal hash table size. Possible values are normal , big and huge. It is also possible to specify a custom hash table size by defining two values and separating them with a comma ','. Command line option: -t HeaderText string Set report header as string. HostName string Set the hostname as string. Normally, HostName is taken from log files, or, in case of Sendmail for NT, from the compile time de- fine HOSTNAME. Command line option: -H IncludeAscii value Include the ASCII report as HTML comment. Possible values are yes or no. Command line option: -i OutFile file Print the report as file. Command line option: -o PictureALT string If PictureURL is defined, set ALT text inside the IMG HTML-tag as string. PictureLink string If PictureURL is defined, make the picture as link pointing to string. PictureParameters string If PictureURL is defined, set additional IMG parameters as string. PictureURL URL Include a picture with source URL as URL in HTML report. The pic- ture appears in a upper left corner of the page. See also PictureParameters , PictureALT and PictureLink keywords. PrintGeneralInfo value Print the General Information section in report. Possible values are yes or no. PrintStatus number Set the number of the top status messages as number. PrintRule number Set the number of the top ruleset rejections as number. PrintTime value Print the Time Distribution section in report. Possible values are yes or no. Command line option: -n RelayPairs number Set the number of the top relay address pairs as number. RelayRecipientFilter string Set relay recipient filter as string. See also EnvelopeRecipientFilter keyword. RelayRecipients number Set the number of the top relay recipients as number. Command line option: -r RelaySenderFilter string Set relay sender filter as string. See also EnvelopeRecipientFilter keyword. RelaySenders number Set the number of the top relay senders as number. Command line option: -r ShowUsers value If value is set as no , process only the domain portion of the email address. Command line option: -d Silent value If value is set as yes , do not print error messages. Command line option: -q Sorting value Set the sort order as value. Possible values are number or transfer. Command line option: -s SyslogTag string Process only lines with syslog tag string. Command line option: -L StartTime date Process log entry only if the date is after date. The format of the date is YYYY/MM/DD-HH:MM:SS. Command line option: -D TbColor RGB Set HTML report table corner color as RGB. FILES sma can as an option use a configuration file. It's default location can be configured using a compile time define DEFAULT CONF in file conf.h. By default, it is defined as ./sma.conf AUTHOR Jarkko Turkulainen BUGS sma takes the year from runtime year. It knows nothing about the new year transitions in log files. The documentation contains a lot of bad english. BSD Experimental October 28, 2001 5 sma-1.4.orig/getopt.c0000644000175000017500000000727107603333515014751 0ustar apollockapollock/* * Copyright (c) 1987, 1993, 1994 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include "sma.h" int opterr = 1, /* if error message should be printed */ sma_optind = 1, /* index into parent argv vector */ optopt, /* character checked for validity */ optreset; /* reset getopt */ const char *sma_optarg; /* argument associated with option */ #define BADCH (int)'?' #define BADARG (int)':' #define EMSG "" /* * getopt -- * Parse argc/argv argument vector. */ int getopt(nargc, nargv, ostr) int nargc; char * const *nargv; const char *ostr; { static const char *place = EMSG; /* option letter processing */ char *oli; /* option letter list index */ if (optreset || !*place) { /* update scanning pointer */ optreset = 0; if (sma_optind >= nargc || *(place = nargv[sma_optind]) != '-') { place = EMSG; return (-1); } if (place[1] && *++place == '-') { /* found "--" */ ++sma_optind; place = EMSG; return (-1); } } /* option letter okay? */ if ((optopt = (int)*place++) == (int)':' || !(oli = strchr(ostr, optopt))) { /* * if the user didn't specify '-' as an option, * assume it means -1. */ if (optopt == (int)'-') return (-1); if (!*place) ++sma_optind; if (opterr && *ostr != ':') (void)fprintf(stderr, "%s: illegal option -- %c\n", pname, optopt); return (BADCH); } if (*++oli != ':') { /* don't need argument */ sma_optarg = NULL; if (!*place) ++sma_optind; } else { /* need an argument */ if (*place) /* no white space */ sma_optarg = place; else if (nargc <= ++sma_optind) { /* no arg */ place = EMSG; if (*ostr == ':') return (BADARG); if (opterr) (void)fprintf(stderr, "%s: option requires an argument -- %c\n", pname, optopt); return (BADCH); } else /* white space */ sma_optarg = nargv[sma_optind]; place = EMSG; ++sma_optind; } return (optopt); /* dump back option letter */ } sma-1.4.orig/hash.c0000644000175000017500000003577407643001043014373 0ustar apollockapollock/* * sma -- Sendmail log analyser * * Copyright (c) 2000 - 2003 Jarkko Turkulainen. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY JARKKO TURKULAINEN ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL JARKKO TURKULAINEN BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $Date: 2003/04/03 12:42:33 $ */ #include "sma.h" /* hash function, stolen from O'Reilly book */ unsigned hash(const char *s, int size) { unsigned val; val = 0; while (*s != '\0') { int tmp; val = (val << 4) + (*s); if ((tmp = (val & 0xf0000000U))) { val = val ^ (tmp >> 24); val = val ^ tmp; } s++; } return val % size; } /* initialize host struct: */ struct host * init_host(const char *s) { struct host *ptr; for (ptr = first.next; ptr; ptr = ptr->next) if (!(strcmp(s, ptr->name))) return ptr; hosts++; /* space: */ if (!(ptr = malloc(sizeof(*ptr)))) error_memory(); if (!(ptr->name = strdup(s))) error_memory(); /* inital values: */ if (!(ptr->etab = malloc(asize * sizeof(struct envpair *)))) error_memory(); memset(ptr->etab, 0, sizeof(struct envpair *) * asize); if (!(ptr->itab = malloc(asize * sizeof(struct in *)))) error_memory(); memset(ptr->itab, 0, sizeof(struct in *) * asize); if (!(ptr->otab = malloc(asize * sizeof(struct out *)))) error_memory(); memset(ptr->otab, 0, sizeof(struct out *) * asize); if (!(ptr->rtab = malloc(rsize * sizeof(struct envpair *)))) error_memory(); memset(ptr->rtab, 0, sizeof(struct envpair *) * rsize); if (!(ptr->ritab = malloc(rsize * sizeof(struct rin *)))) error_memory(); memset(ptr->ritab, 0, sizeof(struct rin *) * rsize); if (!(ptr->rotab = malloc(rsize * sizeof(struct rout *)))) error_memory(); memset(ptr->rotab, 0, sizeof(struct rout *) * rsize); if (!(ptr->sttab = malloc(rsize * sizeof(struct status *)))) error_memory(); memset(ptr->sttab, 0, sizeof(struct status *) * rsize); if (!(ptr->ruletab = malloc(rsize * sizeof(struct rule *)))) error_memory(); memset(ptr->ruletab, 0, sizeof(struct rule *) * rsize); ptr->msgidtab = NULL; ptr->omsgidtab = NULL; ptr->alias = 0; ptr->hopc = 0; ptr->lcerror = 0; ptr->oserror = 0; ptr->dstart = 0; memset(ptr->ihh, 0, sizeof(int) * 24); memset(ptr->fihh, 0, sizeof(float) * 24); memset(ptr->idd, 0, sizeof(int) * 7); memset(ptr->fidd, 0, sizeof(float) * 7); memset(ptr->ohh, 0, sizeof(int) * 24); memset(ptr->fohh, 0, sizeof(float) * 24); memset(ptr->odd, 0, sizeof(int) * 7); memset(ptr->fodd, 0, sizeof(float) * 7); ptr->inum = 0; ptr->onum = 0; ptr->gonum = 0; ptr->rinum = 0; ptr->ronum = 0; ptr->sent = 0; ptr->queu = 0; ptr->hunk = 0; ptr->uunk = 0; ptr->service = 0; ptr->other = 0; ptr->defe = 0; ptr->rule = 0; ptr->size = 0; ptr->isize = 0; ptr->osize = 0; ptr->lsize = 0; ptr->edif = 0; ptr->idif = 0; ptr->odif = 0; ptr->rrdif = 0; ptr->ridif = 0; ptr->rodif = 0; ptr->sdif = 0; ptr->rdif = 0; ptr->fhost = 0; /* utilize next pointer: */ ptr->next = first.next; first.next = ptr; return ptr; } /* update input struct: */ void update_in(struct host *hptr, const char *s, int ssize) { unsigned hashval; struct in *ptr; for (ptr = hptr->itab[hash(s,asize)]; ptr; ptr = ptr->next) if (!strcmp(s, ptr->name)) { ptr->size += ssize; ptr->num++; return; } /* number of _different_ addresses: */ hptr->idif++; /* space: */ if (!(ptr = malloc(sizeof(*ptr)))) error_memory(); if (!(ptr->name = strdup(s))) error_memory(); /* initial values: */ ptr->num = 1; ptr->size = ssize; /* space for next one: */ hashval = hash(s,asize); ptr->next = hptr->itab[hashval]; hptr->itab[hashval] = ptr; } /* remove input structure */ void remove_in(struct host *hptr, const char *s, int size) { unsigned hashval; struct in *ptr, *prev; if (vflag) fprintf(stderr, " removing %s... ", s); hashval = hash(s,asize); prev = NULL; for (ptr = hptr->itab[hashval]; ptr; ptr = ptr->next) { if (!strcmp(s, ptr->name)) { ptr->num--; ptr->size -= size; if (ptr->num) { if (vflag) fprintf(stderr, "OK\n"); return; } if (prev == NULL) hptr->itab[hashval] = ptr->next; else prev->next = ptr->next; free(ptr->name); free(ptr); if (vflag) fprintf(stderr, "OK\n"); hptr->idif--; return; } prev = ptr; } if (vflag) fprintf(stderr, "not found\n"); } /* update output struct: */ void update_out(struct host *hptr, const char *s, int ssize) { unsigned hashval; struct out *ptr; for (ptr = hptr->otab[hash(s,asize)];ptr; ptr = ptr->next) if (!strcmp(s, ptr->name)) { ptr->size += ssize; ptr->num++; return; } hptr->odif++; if (!(ptr = malloc(sizeof(*ptr)))) error_memory(); if (!(ptr->name = strdup(s))) error_memory(); ptr->num = 1; ptr->size = ssize; hashval = hash(s,asize); ptr->next = hptr->otab[hashval]; hptr->otab[hashval] = ptr; } /* update input relay struct: */ void update_rin(struct host *hptr, const char *s, int ssize) { unsigned hashval; struct rin *ptr; if (vflag) fprintf(stderr, " updating input relay %s... ", s); for (ptr = hptr->ritab[hash(s,rsize)];ptr;ptr = ptr->next) if (!strcmp(s, ptr->name)) { ptr->size += ssize; ptr->num++; if (vflag) fprintf(stderr, "OK\n"); return; } if (vflag) fprintf(stderr, "not found, adding.\n"); hptr->ridif++; if (!(ptr = malloc(sizeof(*ptr)))) error_memory(); if (!(ptr->name = strdup(s))) error_memory(); ptr->size = ssize; ptr->num = 1; hashval = hash(s,rsize); ptr->next = hptr->ritab[hashval]; hptr->ritab[hashval] = ptr; } /* remove input relay structure */ void remove_rin(struct host *hptr, const char *s, int size) { unsigned hashval; struct rin *ptr, *prev; if (vflag) fprintf(stderr, " removing %s... ", s); hashval = hash(s,rsize); prev = NULL; for (ptr = hptr->ritab[hashval]; ptr ; ptr = ptr->next) { if (!strcmp(s, ptr->name)) { ptr->num--; ptr->size -= size; if (ptr->num) { if (vflag) fprintf(stderr, "OK\n"); return; } if (prev == NULL) hptr->ritab[hashval] = ptr->next; else prev->next = ptr->next; free(ptr->name); free(ptr); if (vflag) fprintf(stderr, "OK\n"); hptr->ridif--; return; } prev = ptr; } if (vflag) fprintf(stderr, "not found\n"); } /* update output relay struct: */ void update_rout(struct host *hptr, const char *s, int ssize) { unsigned hashval; struct rout *ptr; if (vflag) fprintf(stderr, " updating output relay %s... ", s); for (ptr = hptr->rotab[hash(s,rsize)]; ptr; ptr=ptr->next) if (!strcmp(s, ptr->name)) { ptr->num++; ptr->size += ssize; if (vflag) fprintf(stderr, "OK\n"); return; } if (vflag) fprintf(stderr, "not found, adding.\n"); hptr->rodif++; if (!(ptr = malloc(sizeof(*ptr)))) error_memory(); if (!(ptr->name = strdup(s))) error_memory(); ptr->num = 1; ptr->size = ssize; hashval = hash(s,rsize); ptr->next = hptr->rotab[hashval]; hptr->rotab[hashval] = ptr; } /* update message ID structure */ int update_msgid(struct host *hptr, const char *p, const char *q, const char *s, int m, int k, int n, int size, const char *msg) { struct msgid *ptr; if (vflag) fprintf(stderr, " initializing msgid %s, chain: ", s); for (ptr = hptr->msgidtab; ptr; ptr=ptr->next) { if (!strcmp(s, ptr->id)) { if (vflag) fprintf(stderr, "msgid found!\n"); return(0); } if (vflag) fprintf(stderr, "%s, ", ptr->id); } if (vflag) fprintf(stderr, "\n"); if (!(ptr = malloc(sizeof(*ptr)))) error_memory(); if (!(ptr->sender = strdup(p))) error_memory(); if (!(ptr->relay = strdup(q))) error_memory(); if (!(ptr->id = strdup(s))) error_memory(); if (!(ptr->msgid = strdup(msg))) error_memory(); /* Set delivery flag as "NOT_DELIVERED": */ ptr->flag = 0; ptr->hh = m; ptr->day = k; ptr->num = n; ptr->size = size; /* utilize next pointer: */ ptr->next = hptr->msgidtab; hptr->msgidtab = ptr; return(0); } /* get current message ID structure */ struct msgid * get_msgid(struct host *hptr, const char *s) { struct msgid *ptr; if (vflag) fprintf(stderr, " getting size for msgid %s...", s); for (ptr = hptr->msgidtab; ptr; ptr=ptr->next) if (!strcmp(s, ptr->id)) { if (vflag) fprintf(stderr, " %e\n", (double)ptr->size); return(ptr); } if (vflag) fprintf(stderr, " not found\n"); return(NULL); } /* check message ID structure */ void check_msgid(struct host *hptr, const char *s, int p) { struct msgid *ptr, *prev; if (!p && vflag) fprintf(stderr, " checking %s... ", s); prev = NULL; for (ptr = hptr->msgidtab; ptr; ptr=ptr->next) { if (!strcmp(s, ptr->id)) { if (!p) { ptr->num--; if (vflag) fprintf(stderr, "nr of recipients left: %d\n", ptr->num); } if (ptr->num < 0) ptr->num = 0; if (p && ptr->num == 0) { if (vflag) fprintf(stderr, " %s removed from chain\n", s); if (prev == NULL) hptr->msgidtab = ptr->next; else prev->next = ptr->next; free(ptr->id); free(ptr->sender); free(ptr->relay); free(ptr); } return; } prev = ptr; } if (!p && vflag) fprintf(stderr, "not found\n"); } /* remove message ID structure */ void remove_msgid(struct host *hptr, const char *s) { struct msgid *ptr, *prev; if (vflag) fprintf(stderr, " removing %s... ", s); prev = NULL; for (ptr = hptr->msgidtab; ptr; ptr=ptr->next) { if (!strcmp(s, ptr->id)) { if (vflag) fprintf(stderr, "OK\n"); if (prev == NULL) hptr->msgidtab = ptr->next; else prev->next = ptr->next; free(ptr->id); free(ptr->sender); free(ptr->relay); free(ptr); return; } prev = ptr; } if (vflag) fprintf(stderr, "not found\n"); } /* update out-of-order message ID structure */ int update_omsgid(struct host *hptr, const char *s, int n) { struct omsgid *ptr; if (vflag) fprintf(stderr, " initializing omsgid %s, chain: ", s); for (ptr = hptr->omsgidtab; ptr; ptr=ptr->next) { if (!strcmp(s, ptr->id)) { if (vflag) fprintf(stderr, "omsgid found!\n"); return(0); } if (vflag) fprintf(stderr, "%s, ", ptr->id); } if (vflag) fprintf(stderr, "\n"); if (!(ptr = malloc(sizeof(*ptr)))) error_memory(); if (!(ptr->id = strdup(s))) error_memory(); ptr->flags = n; /* utilize next pointer: */ ptr->next = hptr->omsgidtab; hptr->omsgidtab = ptr; return(0); } /* check out-of-order message ID structure */ int check_omsgid(struct host *hptr, const char *s) { struct omsgid *ptr, *prev; prev = NULL; for (ptr = hptr->omsgidtab; ptr; ptr=ptr->next) { if (!strcmp(s, ptr->id)) { if (vflag) fprintf(stderr, " %s removed from chain\n", s); if (prev == NULL) hptr->omsgidtab = ptr->next; else prev->next = ptr->next; free(ptr->id); free(ptr); return(1); } prev = ptr; } return(0); } /* update status struct: */ void update_status(struct host *hptr, const char *s) { unsigned hashval; struct status *ptr; for (ptr = hptr->sttab[hash(s,rsize)];ptr; ptr = ptr->next) if (!strcmp(s, ptr->name)) { ptr->num++; return; } hptr->sdif++; if (!(ptr = malloc(sizeof(*ptr)))) error_memory(); if (!(ptr->name = strdup(s))) error_memory(); ptr->num = 1; hashval = hash(s,rsize); ptr->next = hptr->sttab[hashval]; hptr->sttab[hashval] = ptr; } /* update ruleset struct: */ void update_ruleset(struct host *hptr, const char *s, const char *p) { unsigned hashval; struct rule *ptr; struct rrelay *rptr; hashval = hash(s,rsize); for (ptr = hptr->ruletab[hashval];ptr; ptr = ptr->next) if (!strcmp(s, ptr->name)) { ptr->num++; /* Update relay table: */ for (rptr = ptr->rrelaytab; rptr; rptr = rptr->next) { if (!strcmp(p, rptr->name)) { rptr->num++; return; } } ptr->reldif++; if (!(rptr = malloc(sizeof(*rptr)))) error_memory(); if (!(rptr->name = strdup(p))) error_memory(); rptr->num = 1; rptr->next = ptr->rrelaytab; ptr->rrelaytab = rptr; return; } /* New entry, set defaults: */ hptr->rdif++; if (!(ptr = malloc(sizeof(*ptr)))) error_memory(); if (!(ptr->name = strdup(s))) error_memory(); ptr->rrelaytab = NULL; /* Set defaults for first relay */ if (!(rptr = malloc(sizeof(*rptr)))) error_memory(); if (!(rptr->name = strdup(p))) error_memory(); rptr->num = 1; rptr->next = ptr->rrelaytab; ptr->rrelaytab = rptr; ptr->num = 1; ptr->reldif = 1; ptr->next = hptr->ruletab[hashval]; hptr->ruletab[hashval] = ptr; } /* update envelope pairs: */ void update_envpair(struct host *hptr, const char *s, const char *p, int ssize) { unsigned hashval; struct envpair *ptr; const char *f; const char *t; char *tmp; char *tmp1; f = s; t = p; if (!(tmp = malloc(strlen(s)+strlen(p)))) error_memory(); tmp1 = tmp; while(*s != '\0') *tmp++ = *s++; while(*p != '\0') *tmp++ = *p++; hashval = hash(t,asize); for (ptr = hptr->etab[hashval];ptr; ptr = ptr->next) if (!strcmp(f, ptr->fname) && !(strcmp(t, ptr->tname))) { ptr->num++; ptr->size += ssize; free(tmp1); return; } hptr->edif++; if (!(ptr = malloc(sizeof(*ptr)))) error_memory(); if (!(ptr->fname = strdup(f))) error_memory(); if (!(ptr->tname = strdup(t))) error_memory(); ptr->num = 1; ptr->size = ssize; ptr->next = hptr->etab[hashval]; hptr->etab[hashval] = ptr; free(tmp1); } /* update relay pairs: */ void update_relpair(struct host *hptr, const char *s, const char *p, int ssize) { unsigned hashval; struct relpair *ptr; const char *f; const char *t; char *tmp; char *tmp1; f = s; t = p; if (!(tmp = malloc(strlen(s)+strlen(p)))) error_memory(); tmp1 = tmp; while(*s != '\0') *tmp++ = *s++; while(*p != '\0') *tmp++ = *p++; hashval = hash(t,rsize); for (ptr = hptr->rtab[hashval];ptr; ptr = ptr->next) if (!strcmp(f, ptr->fname) && !(strcmp(t, ptr->tname))) { ptr->num++; ptr->size += ssize; free(tmp1); return; } hptr->rrdif++; if (!(ptr = malloc(sizeof(*ptr)))) error_memory(); if (!(ptr->fname = strdup(f))) error_memory(); if (!(ptr->tname = strdup(t))) error_memory(); ptr->num = 1; ptr->size = ssize; ptr->next = hptr->rtab[hashval]; hptr->rtab[hashval] = ptr; free(tmp1); } sma-1.4.orig/html.c0000644000175000017500000006541507637062642014426 0ustar apollockapollock/* * sma -- Sendmail log analyser * * Copyright (c) 2000 - 2003 Jarkko Turkulainen. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY JARKKO TURKULAINEN ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL JARKKO TURKULAINEN BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $Date: 2003/03/22 15:30:37 $ */ #include "sma.h" void html(FILE *fp) { unsigned int j, h; struct host *hptr; const char *wdtab[] = { "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" }; const char *hrtab[] = { "00-01", "01-02", "02-03", "03-04", "04-05", "05-06", "06-07", "07-08", "08-09", "09-10", "10-11", "11-12", "12-13", "13-14", "14-15", "15-16", "16-17", "17-18", "18-19", "19-20", "20-21", "21-22", "22-23", "23-00" }; curr = localtime(&tval); fprintf(fp, "\n"); if (iflag) { /* Print embedded ASCII report */ fprintf(fp, "\n"); } fprintf(fp, "\n" " \n" " \n" " \n", VERSION); fprintf(fp, " sendmail log analysis report\n" " \n\n" " \n", bchar); if (puchar) { fprintf(fp, " \n" " \n"); if (plchar) fprintf(fp, " \n", plchar, puchar, pachar ? pachar : PICTURE_ALT, ppchar ? ppchar : ""); else fprintf(fp, " \n", puchar, pachar ? pachar : PICTURE_ALT, ppchar ? ppchar : ""); fprintf(fp, " \n" " \n" "
" "\"%s\"" "\"%s\"

%s

\n", Cchar); if (htchar) fprintf(fp, " %s\n", htchar); else fprintf(fp, " Generated at %s by SMA, " "version %s\n", stripn(asctime(curr)), VERSION); fprintf(fp, "
\n"); } else { fprintf(fp, "

%s

\n", Cchar); if (htchar) fprintf(fp, " %s\n", htchar); else fprintf(fp, " Generated at %s by SMA, " "version %s\n", stripn(asctime(curr)), VERSION); } fprintf(fp, "


\n\n" " \n" "

Index

\n"); for (hptr = first.next; hptr; hptr = hptr->next) { if (!(hptr->inum) || !(hptr->inum)) continue; fprintf(fp, " %s
\n", hptr->name, hptr->name); fprintf(fp, " \n"); } fprintf(fp, "

\n\n"); for (hptr = first.next; hptr; hptr = hptr->next) { if (!(hptr->inum) || !(hptr->inum)) continue; fprintf(fp, " \n", hptr->name); fprintf(fp, "

%s

\n", hptr->name); if (pgflag) { fprintf(fp, " \n", hptr->name); fprintf(fp, " General information
\n" " \n" " \n" " \n", tbchar); fprintf(fp, " \n", stripn(ctime(&hptr->ftime))); fprintf(fp, " \n" " \n" " \n", tbchar); fprintf(fp, " \n", stripn(ctime(&hptr->ltime))); fprintf(fp, " \n" " \n" " \n", tbchar); fprintf(fp, " \n", hptr->alias); fprintf(fp, " \n" " \n" " \n", tbchar); fprintf(fp, " \n", hptr->hopc); fprintf(fp, " \n" " \n" " \n", tbchar); fprintf(fp, " \n", hptr->lcerror); fprintf(fp, " \n" " \n" " \n", tbchar); fprintf(fp, " \n", hptr->oserror); fprintf(fp, " \n" " \n" " \n", tbchar); fprintf(fp, " \n", hptr->rule); fprintf(fp, " \n" " \n" " \n", tbchar); fprintf(fp, " \n", hptr->dstart); fprintf(fp, " \n" "
First log entry%s
Last log entry%s
" "Alias table rebuilds%d
" "Too many hops%d
" "Mail loops%d
" "Other SYSERR%d
" "Ruleset based rejections%d
" "Sendmail daemon restarts%d

\n" " \n" " \n" " \n" " \n" " \n" "
Inbound messages
\n" " \n" " \n" " \n", tbchar); #ifdef _WIN32 fprintf(fp, " \n", (int)hptr->inum); #else fprintf(fp, " \n", hptr->inum); #endif fprintf(fp, " \n" " \n" " \n", tbchar); #ifdef _WIN32 fprintf(fp, " \n", (double)hptr->size/(double)hptr->inum/1000); #else fprintf(fp, " \n", hptr->size/(double)hptr->inum/1000); #endif fprintf(fp, " \n" " \n" " \n", tbchar); fprintf(fp, " \n", 3600*(float)hptr->inum/(float)hptr->dtime); fprintf(fp, " \n" " \n" " \n", tbchar); fprintf(fp, " \n", 60*(float)hptr->inum/(float)hptr->dtime); fprintf(fp, " \n" " \n" " \n", tbchar); fprintf(fp, " \n", (float)hptr->inum/(float)hptr->dtime); fprintf(fp, " \n" "
Total%d%ld
Average size (kB)%.2f%.2Lf
Messages/hour%.2f
Messages/min%.2f
Messages/sec%.2f
\n" "
Outbound messages
\n" " \n" " \n" " \n", tbchar); #ifdef _WIN32 fprintf(fp, " \n", (int)hptr->gonum); #else fprintf(fp, " \n", hptr->gonum); #endif fprintf(fp, " \n" " \n" " \n", tbchar); fprintf(fp, " \n", hptr->sent); fprintf(fp, " \n" " \n" " \n", tbchar); fprintf(fp, " \n", hptr->defe); fprintf(fp, " \n" " \n" " \n", tbchar); fprintf(fp, " \n", hptr->queu); fprintf(fp, " \n" " \n" " \n", tbchar); fprintf(fp, " \n", hptr->other + hptr->hunk + hptr->uunk + hptr->service); fprintf(fp, " \n" "
Total%d%ld
Sent%d
Deferred%d
Queued%d
Other error%d
\n" "

\n\n" " [Index]\n"); fprintf(fp, " [%s]\n\n", hptr->name, hptr->name); } if (epnum) { fprintf(fp, " \n", hptr->name); fprintf(fp, "

Top envelope pairs"); fprintf(fp, "
\n"); fprintf(fp, " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n", tbchar, tbchar, tbchar, tbchar, tbchar); for (j = 0; j < (MIN(epnum, hptr->edif)); j++) { fprintf(fp, " \n"); fprintf(fp, " \n", j+1); fprintf(fp, " \n", hptr->setab[j]->fname, hptr->setab[j]->tname); fprintf(fp, " \n", hptr->setab[j]->num); #ifdef _WIN32 fprintf(fp, " \n", (double)hptr->setab[j]->size/1000000); #else fprintf(fp, " \n", hptr->setab[j]->size/1000000); #endif if (sflag) { fprintf(fp, " \n", 100*(float)hptr->setab[j]->size/(float)hptr->osize); fprintf(fp, " \n"); } else { fprintf(fp, " \n", 100*(float)hptr->setab[j]->num/(float)hptr->onum); fprintf(fp, " \n"); } } fprintf(fp, "
" "NumberSender/Recipient" "Messages" "Transfers (MB)" "%%
%d%s
%s
%d%.2f%.2Lf%.2f
%.2f

\n\n" " [Index]\n"); fprintf(fp, " [%s]\n\n", hptr->name, hptr->name); } if (lnum) { fprintf(fp, " \n", hptr->name); fprintf(fp, "

Top envelope senders"); if (sef) fprintf(fp, " (filter: %s)
\n", sef); else fprintf(fp, "
\n"); fprintf(fp, " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n", tbchar, tbchar, tbchar, tbchar, tbchar); for (j = 0; j < (MIN(lnum, hptr->idif)); j++) { fprintf(fp, " \n"); fprintf(fp, " \n", j+1); fprintf(fp, " \n", hptr->sitab[j]->name); fprintf(fp, " \n", hptr->sitab[j]->num); #ifdef _WIN32 fprintf(fp, " \n", (double)hptr->sitab[j]->size/1000000); #else fprintf(fp, " \n", hptr->sitab[j]->size/1000000); #endif if (sflag) { fprintf(fp, " \n", 100*(float)hptr->sitab[j]->size/(float)hptr->isize); fprintf(fp, " \n"); } else { fprintf(fp, " \n", 100*(float)hptr->sitab[j]->num/(float)hptr->inum); fprintf(fp, " \n"); } } fprintf(fp, "
" "NumberSender" "Messages" "Transfers (MB)" "%%
%d%s%d%.2f%.2Lf%.2f
%.2f

\n\n" " [Index]\n"); fprintf(fp, " [%s]\n\n", hptr->name, hptr->name); } if (lrnum) { fprintf(fp, " \n", hptr->name); fprintf(fp, "

Top envelope recipients"); if (ref) fprintf(fp, " (filter: %s)
\n", ref); else fprintf(fp, "
\n"); fprintf(fp, " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n", tbchar, tbchar, tbchar, tbchar, tbchar); for (j = 0; j < (MIN(lrnum, hptr->odif)); j++) { fprintf(fp, " \n"); fprintf(fp, " \n", j+1); fprintf(fp, " \n", hptr->sotab[j]->name); fprintf(fp, " \n", hptr->sotab[j]->num); #ifdef _WIN32 fprintf(fp, " \n", (double)hptr->sotab[j]->size/1000000); #else fprintf(fp, " \n", hptr->sotab[j]->size/1000000); #endif if (sflag) { fprintf(fp, " \n", 100*(float)hptr->sotab[j]->size/(float)hptr->osize); fprintf(fp, " \n"); } else { fprintf(fp, " \n", 100*(float)hptr->sotab[j]->num/(float)hptr->onum); fprintf(fp, " \n"); } } fprintf(fp, "
" "NumberRecipient" "Messages" "Transfers (MB)" "%%
%d%s%d%.2f%.2Lf%.2f
%.2f

\n\n" " [Index]\n"); fprintf(fp, " [%s]\n\n", hptr->name, hptr->name); } if (rpnum) { fprintf(fp, " \n", hptr->name); fprintf(fp, "

Top relay pairs"); fprintf(fp, "
\n"); fprintf(fp, " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n", tbchar, tbchar, tbchar, tbchar, tbchar); for (j = 0; j < (MIN(rpnum, hptr->rrdif)); j++) { fprintf(fp, " \n"); fprintf(fp, " \n", j+1); fprintf(fp, " \n", hptr->srtab[j]->fname, hptr->srtab[j]->tname); fprintf(fp, " \n", hptr->srtab[j]->num); #ifdef _WIN32 fprintf(fp, " \n", (double)hptr->srtab[j]->size/1000000); #else fprintf(fp, " \n", hptr->srtab[j]->size/1000000); #endif if (sflag) { fprintf(fp, " \n", 100*(float)hptr->srtab[j]->size/(float)hptr->osize); fprintf(fp, " \n"); } else { fprintf(fp, " \n", 100*(float)hptr->srtab[j]->num/(float)hptr->onum); fprintf(fp, " \n"); } } fprintf(fp, "
" "NumberSender relay/Recipient relay" "Messages" "Transfers (MB)" "%%
%d%s
%s
%d%.2f%.2Lf%.2f
%.2f

\n\n" " [Index]\n"); fprintf(fp, " [%s]\n\n", hptr->name, hptr->name); } if (rnum) { fprintf(fp, " \n", hptr->name); fprintf(fp, "

Top relay addresses, sender"); if (srf) fprintf(fp, " (filter: %s)
\n", srf); else fprintf(fp, "
\n"); fprintf(fp, " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n", tbchar, tbchar, tbchar, tbchar, tbchar); for (j = 0; j < (MIN(rnum, hptr->ridif)); j++) { fprintf(fp, " \n"); fprintf(fp, " \n", j+1); fprintf(fp, " \n", hptr->rsitab[j]->name); fprintf(fp, " \n", hptr->rsitab[j]->num); #ifdef _WIN32 fprintf(fp, " \n", (double)hptr->rsitab[j]->size/1000000); #else fprintf(fp, " \n", hptr->rsitab[j]->size/1000000); #endif if (sflag) { fprintf(fp, " \n", 100*(float)hptr->rsitab[j]->size/(float)hptr->isize); } else { fprintf(fp, " \n", 100*(float)hptr->rsitab[j]->num/(float)hptr->rinum); } fprintf(fp, " \n"); } fprintf(fp, "
" "NumberRelay" "Messages" "Transfers (MB)" "%%
%d%s%d%.2f%.2Lf%.2f%.2f

\n\n" " [Index]\n"); fprintf(fp, " [%s]\n\n", hptr->name, hptr->name); } if (rrnum) { fprintf(fp, " \n", hptr->name); fprintf(fp, "

Top relay addresses, recipient"); if (rrf) fprintf(fp, " (filter: %s)
\n", rrf); else fprintf(fp, "
\n"); fprintf(fp, " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n", tbchar, tbchar, tbchar, tbchar, tbchar); for (j = 0; j < (MIN(rrnum, hptr->rodif)); j++) { fprintf(fp, " \n"); fprintf(fp, " \n", j+1); fprintf(fp, " \n", hptr->rsotab[j]->name); fprintf(fp, " \n", hptr->rsotab[j]->num); #ifdef _WIN32 fprintf(fp, " \n", (double)hptr->rsotab[j]->size/1000000); #else fprintf(fp, " \n", hptr->rsotab[j]->size/1000000); #endif if (sflag) { fprintf(fp, " \n", 100*(float)hptr->rsotab[j]->size/(float)hptr->osize); } else { fprintf(fp, " \n", 100*(float)hptr->rsotab[j]->num/(float)hptr->ronum); } fprintf(fp, " \n"); } fprintf(fp, "
" "NumberRelay" "Messages" "Transfers (MB)" "%%
%d%s%d%.2f%.2Lf%.2f%.2f

\n\n" " [Index]\n"); fprintf(fp, " [%s]\n\n", hptr->name, hptr->name); } if (stnum) { fprintf(fp, " \n", hptr->name); fprintf(fp, "

Top status messages"); fprintf(fp, "
\n"); fprintf(fp, " \n" " \n" " \n" " \n" " \n" " \n" " \n", tbchar, tbchar, tbchar, tbchar); for (j = 0; j < (MIN(stnum, hptr->sdif)); j++) { fprintf(fp, " \n"); fprintf(fp, " \n", j+1); fprintf(fp, " \n", hptr->ssttab[j]->num); fprintf(fp, " \n", 100*(float)hptr->ssttab[j]->num/(float)hptr->onum); fprintf(fp, " \n", hptr->ssttab[j]->name); fprintf(fp, " \n"); } fprintf(fp, "
" "NumberMsgs%%" "Status
%d%d%.2f%s

\n\n" " [Index]\n"); fprintf(fp, " [%s]\n\n", hptr->name, hptr->name); } if (rsnum) { fprintf(fp, " \n", hptr->name); fprintf(fp, "

Top ruleset rejections"); fprintf(fp, "
\n"); fprintf(fp, " \n" " \n" " \n" " \n" " \n" " \n" " \n", tbchar, tbchar, tbchar, tbchar, rsrnum ? "Reason / Top relays" : "Reason"); for (j = 0; j < (MIN(rsnum, hptr->rdif)); j++) { fprintf(fp, " \n"); fprintf(fp, " \n", j+1); fprintf(fp, " \n", hptr->sruletab[j]->num); fprintf(fp, " \n", 100*(float)hptr->sruletab[j]->num/(float)hptr->rule); fprintf(fp, " \n"); fprintf(fp, " \n"); if (rsrnum) { for (h = 0; h < (MIN(rsrnum, hptr->sruletab[j]->reldif)); h++) { fprintf(fp, " \n"); fprintf(fp, " \n"); fprintf(fp, " \n", hptr->sruletab[j]->srrelaytab[h]->num); fprintf(fp, " \n", 100*(float)hptr->sruletab[j]->srrelaytab[h]->num/(float)hptr->sruletab[j]->num); fprintf(fp, " \n", hptr->sruletab[j]->srrelaytab[h]->name); fprintf(fp, " \n"); } } } fprintf(fp, "
" "NumberMsgs%%" "%s
%d%d%.2f"); while (*(hptr->sruletab[j]->name) != '\0') { if (*(hptr->sruletab[j]->name) == '<') fprintf(fp, "<"); else if (*(hptr->sruletab[j]->name) == '>') fprintf(fp, ">"); else fputc(*(hptr->sruletab[j]->name), fp); hptr->sruletab[j]->name++; } fprintf(fp, "
%d%.2f%s

\n\n" " [Index]\n"); fprintf(fp, " [%s]\n\n", hptr->name, hptr->name); } if (!nflag) { fprintf(fp, "

\n", hptr->name); fprintf(fp, " \n" " \n" " \n" " \n" " \n" "
Inbound messages per day
\n" " \n" " \n" " \n" " \n" " \n" " \n", tbchar, tbchar, tbchar); for (j = 0; j < 7; j++) { if (hptr->idd[j]) { fprintf(fp, " \n"); fprintf(fp, " \n", tbchar, wdtab[j]); fprintf(fp, " \n", hptr->idd[j]); fprintf(fp, " \n", hptr->fidd[j]); fprintf(fp, " \n"); } } fprintf(fp, "
DayTotalAverage
" "%s%d%.2f
\n" "
Outbound messages per day
\n" " \n" " \n" " \n" " \n" " \n" " \n", tbchar, tbchar, tbchar); for (j = 0; j < 7; j++) { if (hptr->odd[j]) { fprintf(fp, " \n" " \n", tbchar, wdtab[j]); fprintf(fp, " \n", hptr->odd[j]); fprintf(fp, " \n", hptr->fodd[j]); fprintf(fp, " \n"); } } fprintf(fp, "
DayTotalAverage
" "%s%d%.2f
\n" "

\n" " \n" " \n" " \n" " \n" " \n" "
Inbound messages per hour
\n" " \n" " \n" " \n" " \n" " \n" " \n", tbchar, tbchar, tbchar); for (j = 0; j < 24; j++) { if (hptr->ihh[j]) { fprintf(fp, " \n"); fprintf(fp, " \n", tbchar, hrtab[j]); fprintf(fp, " \n", hptr->ihh[j]); fprintf(fp, " \n", hptr->fihh[j]); fprintf(fp, " \n"); } } fprintf(fp, "
HourTotalAverage
" "%s%d%.2f
\n" "
Outbound messages per hour
\n" " \n" " \n" " \n" " \n" " \n" " \n", tbchar, tbchar, tbchar); for (j = 0; j < 24; j++) { if (hptr->ohh[j]) { fprintf(fp, " \n"); fprintf(fp, " \n", tbchar, hrtab[j]); fprintf(fp, " \n", hptr->ohh[j]); fprintf(fp, " \n", hptr->fohh[j]); fprintf(fp, " \n"); } } fprintf(fp, "
HourTotalAverage
" "%s%d%.2f
\n" "

\n\n" " [Index]\n"); fprintf(fp, " [%s]\n\n", hptr->name, hptr->name); } fprintf(fp, "


\n"); } if (ftchar) fprintf(fp, " %s\n", ftchar); else fprintf(fp, " Copyright (c) 2000 - 2003" " Jarkko Turkulainen. All rights reserved.\n"); fprintf(fp, " \n\n"); } sma-1.4.orig/init.c0000644000175000017500000001772607611512042014411 0ustar apollockapollock/* * sma -- Sendmail log analyser * * Copyright (c) 2000 - 2003 Jarkko Turkulainen. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY JARKKO TURKULAINEN ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL JARKKO TURKULAINEN BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $Date: 2002/09/12 11:36:00 $ */ #include "sma.h" int isspace(int); void init(FILE *conf) { char buff[1024]; char *str1, *str2; int k, i, lines; lines = 0; while (fgets(buff, 1024, conf)) { lines++; /* null-terminate: */ buff[strlen(buff)-1] = '\0'; /* skip leading white space: */ for ( i = 0 ; isspace(buff[i]) ; i++) ; /* empty line? */ if (!strlen(&buff[i])) continue; /* comment? */ if (!strncmp("#", &buff[i], 1)) continue; /* fetch key and value: */ k = 0; str1 = get_string(&buff[i]); i += strlen(&buff[i])+1; for ( ; isspace(buff[i]) ; i++ ) ; k = 1; str2 = get_string(&buff[i]); /* if not found... */ if (!strlen(str2)) { if (!qflag) fprintf(stderr, "%s: config file parse" " error, line %d\n", pname, lines); /* Parse configuration keys */ } else { if (!strncmp(str1, "EnvelopePairs", 13)) { epnum = atoi(str2); } else if (!strncmp(str1, "EnvelopeSenders", 15)) { if (!lflag) { lrflag = 1; lnum = atoi(str2); } } else if (!strncmp(str1, "EnvelopeRecipients", 18)) { if (!lflag) { lrflag = 1; lrnum = atoi(str2); } } else if (!strncmp(str1, "RelayPairs", 10)) { rpnum = atoi(str2); } else if (!strncmp(str1, "RelaySenders", 12)) { if (!rflag) { rrflag = 1; rnum = atoi(str2); } } else if (!strncmp(str1, "RelayRecipients", 15)) { if (!rflag) { rrflag = 1; rrnum = atoi(str2); } } else if (!strncmp(str1, "Comment", 7)) { if (!Cflag) if (!(Cchar = strdup(str2))) error_memory(); } else if (!strncmp(str1, "BounceAddress", 13)) { if (!(bechar = strdup(str2))) error_memory(); } else if (!strncmp(str1, "ShowUsers", 9)) { if (strncmp(str2, "yes", 3) && !dflag) dflag = 1; } else if (!strncmp(str1, "Format", 6)) { if (!Oflag) { Oflag = 1; if (!(Ochar = strdup(str2))) error_memory(); } } else if (!strncmp(str1, "HostName", 8)) { if (!Hflag) if(!(Hchar = strdup(str2))) error_memory(); } else if (!strncmp(str1, "BgColor", 7)) { if (!bflag) if (!(bchar = strdup(str2))) error_memory(); } else if (!strncmp(str1, "TbColor", 7)) { if (!(tbchar = strdup(str2))) error_memory(); } else if (!strncmp(str1, "Debug", 5)) { if (!strncmp(str2, "yes", 3) && !vflag) vflag = 1; } else if (!strncmp(str1, "PrintTime", 9)) { if (strncmp(str2, "yes", 3) && !nflag) nflag = 1; } else if (!strncmp(str1, "PrintGeneralInfo", 16)) { if (!strncmp(str2, "no", 3)) pgflag = 0; } else if (!strncmp(str1, "PrintStatus", 11)) { stnum = atoi(str2); } else if (!strncmp(str1, "PrintRuleset", 12)) { rsnum = atoi(str2); } else if (!strncmp(str1, "RulesetRelays", 13)) { rsrnum = atoi(str2); } else if (!strncmp(str1, "OutFile", 7)) { if (!oflag) if (!(ochar = strdup(str2))) error_memory(); } else if (!strncmp(str1, "Sorting", 7)) { if (strncmp(str2, "number", 6) && !sflag) sflag = 1; } else if (!strncmp(str1, "Silent", 6)) { if (!strncmp(str2, "yes", 3) && !qflag) qflag = 1; } else if (!strncmp(str1, "SyslogTag", 9)) { if (!Lflag) if (!(Lchar = strdup(str2))) error_memory(); } else if (!strncmp(str1, "EnvelopeSenderFilter", 20)) { if (!(sef = strdup(str2))) error_memory(); } else if (!strncmp(str1, "EnvelopeRecipientFilter", 23)) { if (!(ref = strdup(str2))) error_memory(); } else if (!strncmp(str1, "RelaySenderFilter", 17)) { if (!(srf = strdup(str2))) error_memory(); } else if (!strncmp(str1, "RelayRecipientFilter", 20)) { if (!(rrf = strdup(str2))) error_memory(); } else if (!strncmp(str1, "StartTime", 9)) { if (!Dflag) if (!(sstring = strdup(str2))) error_memory(); } else if (!strncmp(str1, "EndTime", 7)) { if (!Dflag) if (!(estring = strdup(str2))) error_memory(); } else if (!strncmp(str1, "PictureURL", 10)) { if (!(puchar = strdup(str2))) error_memory(); } else if (!strncmp(str1, "PictureALT", 10)) { if (!(pachar = strdup(str2))) error_memory(); } else if (!strncmp(str1, "PictureParameters", 17)) { if (!(ppchar = strdup(str2))) error_memory(); } else if (!strncmp(str1, "PictureLink", 11)) { if (!(plchar = strdup(str2))) error_memory(); } else if (!strncmp(str1, "HeaderText", 10)) { if (!(htchar = strdup(str2))) error_memory(); } else if (!strncmp(str1, "FooterText", 10)) { if (!(ftchar = strdup(str2))) error_memory(); } else if (!strncmp(str1, "CaseSensitive", 13)) { if (!strncmp(str2, "yes", 3)) csflag = 1; else csflag = 0; } else if (!strncmp(str1, "ClogFormat", 10)) { if (!(cfchar = strdup(str2))) error_memory(); } else if (!strncmp(str1, "ClogSentOnly", 12)) { if (!strncmp(str2, "yes", 3)) clsflag = 1; else clsflag = 0; } else if (!strncmp(str1, "IncludeAscii", 12)) { if (!strncmp(str2, "yes", 3) && !iflag) iflag = 1; } else if (!strncmp(str1, "HashTables", 10)) { if (!tflag) { if(!(tchar = strdup(str2))) error_memory(); tflag = 1; } } else if (!strncmp(str1, "DowncaseAddresses", 17)) { if (!strncmp(str2, "yes", 3) && !dcaddrflag) { dcaddrflag = 1; } } else { if (!qflag) fprintf(stderr, "%s: unknown config parameter" " \"%s\", line %d\n", pname, str1, lines); } } } } /* * Find string, strip off '"'s. */ char * get_string(char *str) { char *tmpstr; char *retstr; int c; /* Malloc space for string: */ if (!(tmpstr = malloc(strlen(str)))) error_memory(); /* check for '"': */ if (*str != '"') c = 0; else c = 1; /* not '"': */ if (!c) { retstr = str; free(tmpstr); while (*str++ != '\0') { if (isspace(*str)) { break; } } *str = '\0'; /* starts with '"': */ } else { retstr = tmpstr; while (*str++ != '\0') { if (*str == '\\' && *(str+1) && *(str+1) == '"') { *tmpstr++ = *(str+1); str++; } else if (*str == '"') break; else *tmpstr++ = *str; } *tmpstr = '\0'; } return retstr; } sma-1.4.orig/install-sh0000755000175000017500000001272007603333515015302 0ustar apollockapollock#!/bin/sh # # install - install a program, script, or datafile # This comes from X11R5 (mit/util/scripts/install.sh). # # Copyright 1991 by the Massachusetts Institute of Technology # # Permission to use, copy, modify, distribute, and sell this software and its # documentation for any purpose is hereby granted without fee, provided that # the above copyright notice appear in all copies and that both that # copyright notice and this permission notice appear in supporting # documentation, and that the name of M.I.T. not be used in advertising or # publicity pertaining to distribution of the software without specific, # written prior permission. M.I.T. makes no representations about the # suitability of this software for any purpose. It is provided "as is" # without express or implied warranty. # # Calling this script install-sh is preferred over install.sh, to prevent # `make' implicit rules from creating a file called install from it # when there is no Makefile. # # This script is compatible with the BSD install script, but was written # from scratch. It can only install one file at a time, a restriction # shared with many OS's install programs. # set DOITPROG to echo to test this script # Don't use :- since 4.3BSD and earlier shells don't like it. doit="${DOITPROG-}" # put in absolute paths if you don't have them in your path; or use env. vars. mvprog="${MVPROG-mv}" cpprog="${CPPROG-cp}" chmodprog="${CHMODPROG-chmod}" chownprog="${CHOWNPROG-chown}" chgrpprog="${CHGRPPROG-chgrp}" stripprog="${STRIPPROG-strip}" rmprog="${RMPROG-rm}" mkdirprog="${MKDIRPROG-mkdir}" transformbasename="" transform_arg="" instcmd="$mvprog" chmodcmd="$chmodprog 0755" chowncmd="" chgrpcmd="" stripcmd="" rmcmd="$rmprog -f" mvcmd="$mvprog" src="" dst="" dir_arg="" while [ x"$1" != x ]; do case $1 in -c) instcmd="$cpprog" shift continue;; -d) dir_arg=true shift continue;; -m) chmodcmd="$chmodprog $2" shift shift continue;; -o) chowncmd="$chownprog $2" shift shift continue;; -g) chgrpcmd="$chgrpprog $2" shift shift continue;; -s) stripcmd="$stripprog" shift continue;; -t=*) transformarg=`echo $1 | sed 's/-t=//'` shift continue;; -b=*) transformbasename=`echo $1 | sed 's/-b=//'` shift continue;; *) if [ x"$src" = x ] then src=$1 else # this colon is to work around a 386BSD /bin/sh bug : dst=$1 fi shift continue;; esac done if [ x"$src" = x ] then echo "install: no input file specified" exit 1 else true fi if [ x"$dir_arg" != x ]; then dst=$src src="" if [ -d $dst ]; then instcmd=: else instcmd=mkdir fi else # Waiting for this to be detected by the "$instcmd $src $dsttmp" command # might cause directories to be created, which would be especially bad # if $src (and thus $dsttmp) contains '*'. if [ -f $src -o -d $src ] then true else echo "install: $src does not exist" exit 1 fi if [ x"$dst" = x ] then echo "install: no destination specified" exit 1 else true fi # If destination is a directory, append the input filename; if your system # does not like double slashes in filenames, you may need to add some logic if [ -d $dst ] then dst="$dst"/`basename $src` else true fi fi ## this sed command emulates the dirname command dstdir=`echo $dst | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'` # Make sure that the destination directory exists. # this part is taken from Noah Friedman's mkinstalldirs script # Skip lots of stat calls in the usual case. if [ ! -d "$dstdir" ]; then defaultIFS=' ' IFS="${IFS-${defaultIFS}}" oIFS="${IFS}" # Some sh's can't handle IFS=/ for some reason. IFS='%' set - `echo ${dstdir} | sed -e 's@/@%@g' -e 's@^%@/@'` IFS="${oIFS}" pathcomp='' while [ $# -ne 0 ] ; do pathcomp="${pathcomp}${1}" shift if [ ! -d "${pathcomp}" ] ; then $mkdirprog "${pathcomp}" else true fi pathcomp="${pathcomp}/" done fi if [ x"$dir_arg" != x ] then $doit $instcmd $dst && if [ x"$chowncmd" != x ]; then $doit $chowncmd $dst; else true ; fi && if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dst; else true ; fi && if [ x"$stripcmd" != x ]; then $doit $stripcmd $dst; else true ; fi && if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dst; else true ; fi else # If we're going to rename the final executable, determine the name now. if [ x"$transformarg" = x ] then dstfile=`basename $dst` else dstfile=`basename $dst $transformbasename | sed $transformarg`$transformbasename fi # don't allow the sed command to completely eliminate the filename if [ x"$dstfile" = x ] then dstfile=`basename $dst` else true fi # Make a temp file name in the proper directory. dsttmp=$dstdir/#inst.$$# # Move or copy the file name to the temp name $doit $instcmd $src $dsttmp && trap "rm -f ${dsttmp}" 0 && # and set any options; do chmod last to preserve setuid bits # If any of these fail, we abort the whole thing. If we want to # ignore errors from any of these, just make sure not to ignore # errors from the above "$doit $instcmd $src $dsttmp" command. if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; else true;fi && if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; else true;fi && if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; else true;fi && if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; else true;fi && # Now rename the file to the real destination. $doit $rmcmd -f $dstdir/$dstfile && $doit $mvcmd $dsttmp $dstdir/$dstfile fi && exit 0 sma-1.4.orig/parse.c0000644000175000017500000005657507652750020014572 0ustar apollockapollock/* * sma -- Sendmail log analyser * * Copyright (c) 2000 - 2003 Jarkko Turkulainen. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY JARKKO TURKULAINEN ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL JARKKO TURKULAINEN BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $Date: 2003/04/27 15:43:33 $ */ #include "sma.h" #include /* Delivery status flags */ #define STATUS_SENT 1 #define STATUS_DEF 2 #define STATUS_USER 3 #define STATUS_QUEUE 4 #define STATUS_HOST 5 #define STATUS_SERV 6 #define STATUS_OTHER 7 /* Message ID flags: */ #define NOT_DELIVERED 0 #define FIRST_DELIVERY 1 #define DELIVERED 2 /* Message ID checking mode */ #define KEEP 0 #define REMOVE 1 /* Action flags */ #define ACTION_FROM 0 #define ACTION_TO 1 #define ACTION_SYSERR 2 #define ACTION_RULESET 3 #define ACTION_DAEMON 4 #define ACTION_DATAB 5 #define ACTION_DSN 6 #define ACTION_USER 7 #define ACTION_UNKNOWN 100 /* ACTION_SYSERR flags */ #define OTHER 0 #define HOPCOUNT 1 #define LOOP 2 #ifdef USE_REGEXP int check_filter(const char *, regex_t *, const char *); #else int check_filter(const char *, const char *); #endif /* * Do parsing for each input file */ void parse(FILE *fp, const char *file) { /* input buffer */ char line[2048]; /* plenty of pointers for line splitting: */ static const char *env_rec[128]; char *head[64]; char *info[64]; /* collecting */ char *action, *dsn, *idptr; char *messageid = NULL; const char *tmphost; int logformat, hcount, icount; int status = 0, idsize = 0, gf, pf = 0, actn = 0, sunos = 0; int actflag, year, mon, day, hh, min, sec; struct msgid *tmsgid = NULL; /* general purpose: */ const char *p = NULL; const char *s = NULL; int i, k, lcount; /* status and ruleset pointers */ const char *rulestr = NULL; const char *relstr = NULL; const char *statstr = NULL; /* temporary pointer to host struct: */ struct host *hptr; /* Start read file line by line: */ lcount = 0; while (fgets(line, 2048, fp)) { lcount++; /* null-terminate: */ line[strlen(line)-1] = '\0'; memset(head, 0, 64); memset(info, 0, 64); /* split line initially with ',': */ info[0] = line; for (i = 1, k = 0; line[k] != '\0'; ) { if (line[k] == ',') { line[k] = '\0'; k++; if (line[k] == ' ') k++; info[i] = &line[k]; i++; } else k++; } icount = i; /* split first info with ' ': */ head[0] = info[0]; for (i = 1, k = 0; info[0][k] != '\0'; ) { if (info[0][k] == ' ') { info[0][k] = '\0'; k++; while(info[0][k] == ' ') k++; head[i] = &info[0][k]; i++; } else k++; } hcount = i; /* * Initial sanity check: * Try to figure out the input file format * Currently supported are syslog and NT * * Sendmail for NT * Assume that the second field is "sendmail" .. * This may be wrong, don't know NT version enough. */ idptr = NULL; action = NULL; actn = 0; dsn = NULL; if (head[5] && !strncmp("sendmail", head[2], 7)) { logformat = 1; if (sscanf(head[1], "%d:%d:%d", &hh, &min, &sec) != 3) { if (!qflag) fprintf(stderr, "%s: not NT log, skipping line %d, " "file %s\n", pname, lcount, file); continue; } if (sscanf(head[0], "%d/%d/%d",&mon,&day,&year) != 3) { if (!qflag) fprintf(stderr, "%s: not NT log, skipping line %d, " "file %s\n", pname, lcount, file); continue; } /* We assume things fixed with NT log.. */ if (hcount >= 6) { idptr = head[4]; action = head[5]; actn = 5; dsn = head[6]; mon--; } /* * Normal syslog */ } else { logformat = 0; if (!head[5] || (Lchar && strncmp(Lchar, head[4], strlen(Lchar)))) { if (!qflag) fprintf(stderr, "%s: not syslog, skipping line %d, " "file %s\n", pname, lcount, file); continue; } if (sscanf(head[2], "%d:%d:%d", &hh, &min, &sec) != 3) { if (!qflag) fprintf(stderr, "%s: not syslog, skipping line %d, " "file %s\n", pname, lcount, file); continue; } day = atoi(head[1]); mon = conv_mon(head[0]); /* SunOS 5.x with ID generation enabled: */ if (!strncmp("[ID", head[5], 3)) { sunos = 3; } else sunos = 0; /* * Now, we run through the first info-vector (head) * and try to find useful keywords. If found, copy * the pointers as idptr, action and dsn. Action * flags are later set according to these keywords. */ for (k = 6+sunos; k < hcount; k++ ) { /* "normal" delivery lines */ if (!strncmp("daemon", head[k], 6) || !strncmp("ruleset", head[k], 7) || !strncmp("to=", head[k], 3) || !strncmp("from=", head[k], 5) || !strncmp("SYSERR", head[k], 6) || !strncmp("database", head[k], 8)) { actn = k; idptr = head[k-1]; action = head[k]; break; /* DSN, and other strange stuff: */ } else if (!strncmp("DSN", head[k], 3) || !strncmp("User", head[k], 4) || !strncmp("postmaster", head[k],10) || !strncmp("return", head[k], 6)) { idptr = head[k-2]; action = head[k-1]; dsn = head[k]; break; } } } /* * Permitted actions are defined here. * * We test the action, dsn, idptr and other fields for * keywords and set the flag actflag according to a * defined action. These actions are later performed * with a switch(actflag) statement. * */ actflag = ACTION_UNKNOWN; if (idptr && !strncmp("ruleset", idptr, 7)) { actflag = ACTION_RULESET; } else if (action && !strncmp("ruleset", action, 7)) { actflag = ACTION_RULESET; } else if (action && !strncmp("from=", action, 5)) { actflag = ACTION_FROM; } else if (action && !strncmp("to=", action, 3)) { actflag = ACTION_TO; } else if (action && !strncmp("SYSERR", action, 6)) { actflag = ACTION_SYSERR; } else if (action && !strncmp("daemon", action, 6)) { actflag = ACTION_DAEMON; } else if (action && !strncmp("database", action, 8)) { actflag = ACTION_DATAB; } else if (dsn && (!strncmp("User", dsn, 4))) { actflag = ACTION_USER; } else if (dsn) { actflag = ACTION_DSN; } else continue; /* * Initialize the host structure * If the hostname is not given, use syslog or * (in case of NT) default string */ if (Hchar) tmphost = Hchar; else if (logformat) tmphost = HOSTNAME; else tmphost = head[3]; hptr = init_host(tmphost); /* * Rejected before SMTP "MAIL FROM" * This should be under switch(actflag) but isn't really * a delivery, so we test it here.. */ if (!strncmp("ruleset", idptr, 7)) { hptr->rule++; /* Find the reject-field: */ for (k = 1; k < icount; k++ ) { if (!strncmp("relay=", info[k], 6)) relstr = get_relay_name(info[k]+6); else if (!strncmp("reject=", info[k], 7)) rulestr = info[k]+7; } if (!rulestr) continue; if (!relstr) relstr = BOUNCE_HOST; if (rsnum) update_ruleset(hptr, rulestr, relstr); continue; } /* Take the current time: */ hptr->cdtime = (time_t)conv_time(mon, day, hh, min, sec); /* Check if we are allowed to proceed: */ if (sstime && (hptr->cdtime < sstime)) continue; if (eetime && (hptr->cdtime > eetime)) continue; /* is the host brand new? */ if (hptr->fhost == 0) { /* Make the first time as ftime, cdtime and ltime: */ hptr->fhost = 1; hptr->ftime = hptr->cdtime; hptr->ltime = hptr->ftime; } /* Check ftime and ltime: */ if (hptr->cdtime > hptr->ltime) hptr->ltime = hptr->cdtime; if (hptr->cdtime < hptr->ftime) hptr->ftime = hptr->cdtime; /* Calculate weekday: */ hptr->lday = (localtime(&hptr->cdtime))->tm_wday; /* Debug */ if (vflag && (actflag == ACTION_DSN || actflag == ACTION_FROM || actflag == ACTION_TO || actflag == ACTION_RULESET || actflag == ACTION_USER)) { fprintf(stderr, "\n<< DEBUG >> file %s, line %d\n", file, lcount); fprintf(stderr, " msg id=%s\n", idptr); } /* * Switch the possible actions * DSN stuff * These include DSN, postmaster notify, return to sender... */ switch(actflag) { case ACTION_DSN: if (vflag) fprintf(stderr, " DSN: %s\n", idptr); /* Find the message ID */ tmsgid = get_msgid(hptr, idptr); if (tmsgid == NULL) continue; /* Remove it */ remove_msgid(hptr, idptr); /* This is a completely new mail */ p = bechar; s = BOUNCE_HOST; /* * Sender Envelope and Relay filtering */ #ifdef USE_REGEXP if (check_filter(sef, &csef, p) && check_filter(srf, &csrf, s)) { #else if (check_filter(sef, p) && check_filter(srf, s)) { #endif /* Message ID */ update_msgid(hptr, p, s, action, hh, day, 1, 200, ""); /* Nope, we are filtered: */ } else continue; break; /* User unkown: */ case ACTION_USER: if (vflag) fprintf(stderr, " User unkown: %s\n", idptr); update_omsgid(hptr, idptr, 0); break; /* "from" envelope: */ case ACTION_FROM: p = NULL; s = NULL; /* check omsgidtab */ if (check_omsgid(hptr, idptr)) continue; /* fetch the name: */ p = get_name(action+5); if (vflag) fprintf(stderr, " from=%s\n", p); /* follow on: */ for (k = 1; k < icount; k++) { /* size of the message: */ if (!strncmp("size", info[k], 4)) { hptr->lsize = atoi(info[k]+5); /* msgid */ } else if (!strncmp("msgid", info[k], 5)) { messageid = info[k]+6; /* input relay */ } else if (!strncmp("relay", info[k], 5)) { s = get_relay_name(info[k]+6); /* no of recipients to follow */ } else if (!strncmp("nrcpts", info[k], 6)) idsize = atoi(info[k]+7); } /* Check relay */ if (!s) s = BOUNCE_HOST; if (vflag) fprintf(stderr, " relay=%s\n", s); /* Initialize messageid */ if (!messageid) messageid = ""; /* * Sender Envelope and Relay filtering */ #ifdef USE_REGEXP if (check_filter(sef, &csef, p) && check_filter(srf, &csrf, s)) { #else if (check_filter(sef, p) && check_filter(srf, s)) { #endif update_msgid(hptr, p, s, idptr, hh, day, idsize, hptr->lsize, messageid); /* Nope, we are filtered: */ } else continue; break; /* "to" envelpe: */ case ACTION_TO: p = NULL; s = NULL; /* Check msgidtab */ tmsgid = get_msgid(hptr, idptr); if (tmsgid == NULL) /* Bogus address or (from=) side filter */ continue; hptr->lsize = tmsgid->size; /* Check delivery flag: */ if (tmsgid->flag == NOT_DELIVERED) /* This is a fresh one: */ tmsgid->flag = FIRST_DELIVERY; /* fetch name and make entry: */ i = 0; memset(env_rec, 0, (size_t)sizeof(char) * 128); p = get_name(action+3); env_rec[i] = p; for (k = 1; k < icount; k++) { if (!strncmp("delay", info[k], 5) || !strncmp("ctladdr", info[k], 7)) break; else /* more recipients: */ env_rec[++i] = get_name(info[k]); } /* now for the rest of the cases: */ for (; k < icount; k++ ) { if (!strncmp("stat", info[k], 4)) { statstr = info[k]+5; if (!strncmp("Sent", info[k]+5, 4) || !strncmp("sent", info[k]+5, 4)) status = STATUS_SENT; else if (!strncmp("Deferred", info[k]+5, 8)) status = STATUS_DEF; else if (!strncmp("User", info[k]+5, 4)) status = STATUS_USER; else if (!strncmp("Host", info[k]+5, 4)) status = STATUS_HOST; else if (!strncmp("queued", info[k]+5, 6)) status = STATUS_QUEUE; else if (!strncmp("Service", info[k]+5, 7)) status = STATUS_SERV; else status = STATUS_OTHER; } else if (!strncmp("relay", info[k], 5)) { /* output relay */ s = get_relay_name(info[k]+6); } } /* If no relay host, make as bouncehost: */ if (!s) s = BOUNCE_HOST; if (vflag) fprintf(stderr, " relay=%s\n", s); i = 0; gf = 0; while (env_rec[i]) { if (vflag) fprintf(stderr, " to=%s\n", env_rec[i]); /* * Recipient Envelope and Relay filtering */ #ifdef USE_REGEXP if (check_filter(ref, &cref, env_rec[i]) && check_filter(rrf, &crrf, s)) { gf = 1; pf = 1; #else if (check_filter(ref, env_rec[i]) && check_filter(rrf, s)) { gf = 1; pf = 1; #endif } else pf = 0; if (pf) { /* * Update output side stats if * the format is ASCII or HTML: */ if (Oflag != FORMAT_CLOG) { if (status == STATUS_SENT) { update_out(hptr, env_rec[i], hptr->lsize); if (epnum) update_envpair(hptr, tmsgid->sender, env_rec[i], hptr->lsize); } else { update_out(hptr, env_rec[i], 0); if (epnum) update_envpair(hptr, tmsgid->sender, env_rec[i], 0); } hptr->onum++; /* Custom log: */ } else if (!clsflag || (clsflag && (status == STATUS_SENT))) { printclog( hptr->cdtime, tmphost, (int)hptr->lsize, tmsgid->msgid, tmsgid->sender, tmsgid->relay, env_rec[i], s, (status == STATUS_SENT) ? 1 : 0); } /* Checkout msgid */ check_msgid(hptr, idptr, KEEP); } i++; } /* Remove msgid if not ASCII or HTML: */ if (Oflag == FORMAT_CLOG) { if (gf) { if (status == STATUS_SENT) check_msgid(hptr, idptr, REMOVE); } else /* Remove useless message ID: */ remove_msgid(hptr, idptr); continue; } /* * Update global stats only once per delivery */ if (gf) { /* Update output relay: */ hptr->ronum++; if (status == STATUS_SENT) { update_rout(hptr, s, hptr->lsize); /* update relay pairs */ if (rpnum) update_relpair(hptr, tmsgid->relay, s, hptr->lsize); } else { update_rout(hptr, s, 0); if (rpnum) update_relpair(hptr, tmsgid->relay, s, 0); } /* Update the global stats: */ hptr->gonum++; hptr->ohh[hh]++; hptr->odd[hptr->lday]++; if (status == STATUS_SENT) hptr->osize += hptr->lsize; /* Check status flag: */ if (status == STATUS_SENT) { hptr->sent++; if (stnum) update_status(hptr, "Sent"); } else { if (stnum) update_status(hptr, statstr); switch(status) { case STATUS_DEF: hptr->defe++; break; case STATUS_HOST: hptr->hunk++; break; case STATUS_USER: hptr->uunk++; break; case STATUS_QUEUE: hptr->queu++; break; case STATUS_SERV: hptr->service++; break; case STATUS_OTHER: hptr->other++; break; } } /* * If this is a first delivery, update * input side statistics: */ if (tmsgid->flag == FIRST_DELIVERY) { /* Add envelope: */ hptr->inum++; update_in(hptr, tmsgid->sender, hptr->lsize); /* Add relay: */ hptr->rinum++; update_rin(hptr, tmsgid->relay, hptr->lsize); /* Update statistics: */ hptr->ihh[tmsgid->hh]++; hptr->idd[hptr->lday]++; hptr->size += hptr->lsize; hptr->isize += hptr->lsize; tmsgid->flag = DELIVERED; } /* * If the message was sent, remove useless * message ID from the chain */ if (status == STATUS_SENT) check_msgid(hptr, idptr, REMOVE); } else /* Remove useless message ID: */ remove_msgid(hptr, idptr); break; /* SYSERR: */ case ACTION_SYSERR: if (vflag) { fprintf(stderr, "\n<< DEBUG >> file %s, line %d\n", file, lcount); fprintf(stderr, " SYSERR"); } for (i = 0, k = actn; k < hcount; k++) { /* Too many hops: */ if (!strncmp("Too", head[k], 3)) { if (!head[k+2]) continue; if (!strncmp("many", head[k+1], 4) && !strncmp("hops", head[k+2], 4)) i = HOPCOUNT; /* Local configuration error: */ } else if (!strncmp("config", head[k], 6)) { if (!head[k+1]) continue; if (!strncmp("error:", head[k+1], 6)) i = LOOP; } /* Other SYSERR (i = 0)*/ } switch(i) { case HOPCOUNT: if (vflag) fprintf(stderr, " (hop count)\n"); hptr->hopc++; break; case LOOP: if (vflag) fprintf(stderr, " (mail loop)\n"); hptr->lcerror++; break; case OTHER: if (vflag) fprintf(stderr, " (other)\n"); hptr->oserror++; break; } break; /* ruleset based rejection: */ case ACTION_RULESET: if (vflag) fprintf(stderr, " ruleset: %s\n", idptr); update_omsgid(hptr, idptr, 0); hptr->rule++; /* Find the reject-field: */ for (k = 1; k < icount; k++ ) { if (!strncmp("relay=", info[k], 6)) relstr = get_relay_name(info[k]+6); else if (!strncmp("reject=", info[k], 7)) rulestr = info[k]+7; } if (!rulestr) continue; if (!relstr) relstr = BOUNCE_HOST; if (rsnum) update_ruleset(hptr, rulestr, relstr); break; /* sendmail daemon started: */ case ACTION_DAEMON: if (vflag) { fprintf(stderr, "\n<< DEBUG >> file %s, line %d\n", file, lcount); fprintf(stderr, " daemon restart\n"); } hptr->dstart++; break; /* alias database rebuild: */ case ACTION_DATAB: if (vflag) { fprintf(stderr, "\n<< DEBUG >> file %s, line %d\n", file, lcount); fprintf(stderr, " alias table rebuilt\n"); } hptr->alias++; break; default: continue; } } } /* * get_name - strip sender/recipient name/domain. */ const char * get_name(char *name) { char *tmp, *tmp2; int i; /* downcase everything if requested */ if (dcaddrflag) { for ( i=0; name[i]; i++) { name[i] = tolower(name[i]); } } /* null-sender? */ if (!strncmp("<>", name, 2)) return("<>"); /* find the separating '@'-char: */ while (*name == '<' || *name == '"' || *name == '\'') name++; tmp = tmp2 = name; while (*name++ != '@' && *name) ; if (!*name) name = tmp; /* find the first char of the return pointer: */ if (dflag) tmp = name; else { while (name != tmp2) { if ((*name == '<') || (*name == '"') || (*name == '\'') || (*name == ' ')) { name++; break; } else name--; } tmp = name; } /* cut the string: */ while (*name) { if ((*name == '>') || (*name == '"') || (*name == '\'') || (*name == ' ')) { *name = '\0'; break; } else name++; } return tmp; } /* get relay name: */ const char * get_relay_name(char *name) { char *tmp; tmp = name; /* * Search for space or (in case of identd) * '@'-char. Make the return string point * to next char. */ while (*name) { if (*name == '@') { tmp = name + 1; break; } name++; } if (!*name) name = tmp; /* * Do not take the IP-address in brackets */ while (*name) { if ((*name == ' ') || (*name == ',')) { *name = '\0'; break; } else name++; } if (*(name-1) == '.') *(name-1) = '\0'; return tmp; } #ifdef USE_REGEXP int check_filter(const char *s, regex_t *rgp, const char *text) { if (!s) return(1); else if (*s == '!') { if (!regexec(rgp, text, 0, NULL, 0)) return(0); else return(1); } else if (!regexec(rgp, text, 0, NULL, 0)) return(1); else return(0); } #else int check_filter(const char *s, const char *text) { if (!s) return(1); else if (*s == '!') { if (strstr(text, s+1)) return(0); else return(1); } else if (strstr(text, s)) return(1); else return(0); } #endif /* * Printing routine for Custom Log format */ void printclog(time_t sma_time, const char *host, int size, const char *id, const char *from, const char *frelay, const char *to, const char *trelay, int status) { /* time struct: */ struct tm *tmptime; /* Month tab */ const char *montab[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; /* Temporary pointer */ const char *frm; /* default format: */ if (!cfchar) { fprintf(ofp, "%d %s %d %s %s %s %s %d\n", (int)sma_time, host, size, from, frelay, to, trelay, status); /* We have the format string */ } else { /* Break down the time struct: */ tmptime = localtime(&sma_time); for (frm = cfchar; *frm != '\0'; frm++) switch (*frm) { /* * If the char after '%'-char is something we know * print it, otherwise print literally */ case '%': if (*(frm+1)) switch (*(frm+1)) { case 'd': fprintf(ofp,"%.2d", tmptime->tm_mday); frm++; break; case 'D': fprintf(ofp,"%s", stripn(asctime(tmptime))); frm++; break; case 'f': fprintf(ofp,"%s", from); frm++; break; case 'F': fprintf(ofp, "%s", frelay); frm++; break; case 'h': fprintf(ofp,"%.2d", tmptime->tm_hour); frm++; break; case 'H': fprintf(ofp,"%s", host); frm++; break; case 'i': fprintf(ofp,"%s", id); frm++; break; case 'm': fprintf(ofp,"%.2d", tmptime->tm_mon+1); frm++; break; case 'n': fprintf(ofp,"%.2d", tmptime->tm_min); frm++; break; case 'M': fprintf(ofp,"%s", montab[tmptime->tm_mon]); frm++; break; case 's': fprintf(ofp,"%.2d", tmptime->tm_sec); frm++; break; case 'S': fprintf(ofp,"%d", status); frm++; break; case 't': fprintf(ofp,"%s", to); frm++; break; case 'T': fprintf(ofp,"%s", trelay); frm++; break; case 'U': fprintf(ofp,"%d", (int)sma_time); frm++; break; case 'z': fprintf(ofp,"%d", size); frm++; break; case 'y': fprintf(ofp,"%d", tmptime->tm_year + 1900); frm++; break; case '%': fputc('%', ofp); frm++; break; default: fputc('%', ofp); break; } break; /* backslashed special characters: */ case '\\': if (*(frm+1)) switch (*(frm+1)) { case 'n': fputc('\n', ofp); frm++; break; case 't': fputc('\t', ofp); frm++; break; case '\\': fputc('\\', ofp); frm++; break; default: fputc(*(frm+1), ofp); frm++; break; } break; /* * If not flag or any other special char, copy the * format string character to stream: */ default: fputc(*frm, ofp); break; } /* End line always with newline: */ fputc('\n', ofp); /* Flush output stream */ fflush(ofp); } } sma-1.4.orig/regex/0000755000175000017500000000000007603333515014406 5ustar apollockapollocksma-1.4.orig/regex/COPYRIGHT0000644000175000017500000000551607603333515015710 0ustar apollockapollockCopyright 1992, 1993, 1994 Henry Spencer. All rights reserved. This software is not subject to any license of the American Telephone and Telegraph Company or of the Regents of the University of California. Permission is granted to anyone to use this software for any purpose on any computer system, and to alter it and redistribute it, subject to the following restrictions: 1. The author is not responsible for the consequences of use of this software, no matter how awful, even if they arise from flaws in it. 2. The origin of this software must not be misrepresented, either by explicit claim or by omission. Since few users ever read sources, credits must appear in the documentation. 3. Altered versions must be plainly marked as such, and must not be misrepresented as being the original software. Since few users ever read sources, credits must appear in the documentation. 4. This notice may not be removed or altered. =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= /*- * Copyright (c) 1994 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * @(#)COPYRIGHT 8.1 (Berkeley) 3/16/94 */ sma-1.4.orig/regex/cclass.h0000644000175000017500000000565107603333515016036 0ustar apollockapollock/*- * Copyright (c) 1992, 1993, 1994 Henry Spencer. * Copyright (c) 1992, 1993, 1994 * The Regents of the University of California. All rights reserved. * * This code is derived from software contributed to Berkeley by * Henry Spencer. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * @(#)cclass.h 8.3 (Berkeley) 3/20/94 */ /* character-class table */ static struct cclass { char *name; char *chars; char *multis; } cclasses[] = { { "alnum", "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz\ 0123456789", ""} , { "alpha", "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz", ""} , { "blank", " \t", ""} , { "cntrl", "\007\b\t\n\v\f\r\1\2\3\4\5\6\16\17\20\21\22\23\24\ \25\26\27\30\31\32\33\34\35\36\37\177", ""} , { "digit", "0123456789", ""} , { "graph", "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz\ 0123456789!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~", ""} , { "lower", "abcdefghijklmnopqrstuvwxyz", ""} , { "print", "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz\ 0123456789!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~ ", ""} , { "punct", "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~", ""} , { "space", "\t\n\v\f\r ", ""} , { "upper", "ABCDEFGHIJKLMNOPQRSTUVWXYZ", ""} , { "xdigit", "0123456789ABCDEFabcdef", ""} , { NULL, 0, "" } }; sma-1.4.orig/regex/cname.h0000644000175000017500000001047607603333515015652 0ustar apollockapollock/*- * Copyright (c) 1992, 1993, 1994 Henry Spencer. * Copyright (c) 1992, 1993, 1994 * The Regents of the University of California. All rights reserved. * * This code is derived from software contributed to Berkeley by * Henry Spencer. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * @(#)cname.h 8.3 (Berkeley) 3/20/94 */ /* character-name table */ static struct cname { char *name; char code; } cnames[] = { { "NUL", '\0' }, { "SOH", '\001' }, { "STX", '\002' }, { "ETX", '\003' }, { "EOT", '\004' }, { "ENQ", '\005' }, { "ACK", '\006' }, { "BEL", '\007' }, { "alert", '\007' }, { "BS", '\010' }, { "backspace", '\b' }, { "HT", '\011' }, { "tab", '\t' }, { "LF", '\012' }, { "newline", '\n' }, { "VT", '\013' }, { "vertical-tab", '\v' }, { "FF", '\014' }, { "form-feed", '\f' }, { "CR", '\015' }, { "carriage-return", '\r' }, { "SO", '\016' }, { "SI", '\017' }, { "DLE", '\020' }, { "DC1", '\021' }, { "DC2", '\022' }, { "DC3", '\023' }, { "DC4", '\024' }, { "NAK", '\025' }, { "SYN", '\026' }, { "ETB", '\027' }, { "CAN", '\030' }, { "EM", '\031' }, { "SUB", '\032' }, { "ESC", '\033' }, { "IS4", '\034' }, { "FS", '\034' }, { "IS3", '\035' }, { "GS", '\035' }, { "IS2", '\036' }, { "RS", '\036' }, { "IS1", '\037' }, { "US", '\037' }, { "space", ' ' }, { "exclamation-mark", '!' }, { "quotation-mark", '"' }, { "number-sign", '#' }, { "dollar-sign", '$' }, { "percent-sign", '%' }, { "ampersand", '&' }, { "apostrophe", '\'' }, { "left-parenthesis", '(' }, { "right-parenthesis", ')' }, { "asterisk", '*' }, { "plus-sign", '+' }, { "comma", ',' }, { "hyphen", '-' }, { "hyphen-minus", '-' }, { "period", '.' }, { "full-stop", '.' }, { "slash", '/' }, { "solidus", '/' }, { "zero", '0' }, { "one", '1' }, { "two", '2' }, { "three", '3' }, { "four", '4' }, { "five", '5' }, { "six", '6' }, { "seven", '7' }, { "eight", '8' }, { "nine", '9' }, { "colon", ':' }, { "semicolon", ';' }, { "less-than-sign", '<' }, { "equals-sign", '=' }, { "greater-than-sign", '>' }, { "question-mark", '?' }, { "commercial-at", '@' }, { "left-square-bracket", '[' }, { "backslash", '\\' }, { "reverse-solidus", '\\' }, { "right-square-bracket", ']' }, { "circumflex", '^' }, { "circumflex-accent", '^' }, { "underscore", '_' }, { "low-line", '_' }, { "grave-accent", '`' }, { "left-brace", '{' }, { "left-curly-bracket", '{' }, { "vertical-line", '|' }, { "right-brace", '}' }, { "right-curly-bracket", '}' }, { "tilde", '~' }, { "DEL", '\177' }, { NULL, 0 } }; sma-1.4.orig/regex/engine.c0000644000175000017500000007037007603333515016026 0ustar apollockapollock/*- * Copyright (c) 1992, 1993, 1994 Henry Spencer. * Copyright (c) 1992, 1993, 1994 * The Regents of the University of California. All rights reserved. * * This code is derived from software contributed to Berkeley by * Henry Spencer. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * @(#)engine.c 8.5 (Berkeley) 3/20/94 */ /* * The matching engine and friends. This file is #included by regexec.c * after suitable #defines of a variety of macros used herein, so that * different state representations can be used without duplicating masses * of code. */ #ifdef SNAMES #define matcher smatcher #define fast sfast #define slow sslow #define dissect sdissect #define backref sbackref #define step sstep #define print sprint #define at sat #define match smat #endif #ifdef LNAMES #define matcher lmatcher #define fast lfast #define slow lslow #define dissect ldissect #define backref lbackref #define step lstep #define print lprint #define at lat #define match lmat #endif /* another structure passed up and down to avoid zillions of parameters */ struct match { struct re_guts *g; int eflags; regmatch_t *pmatch; /* [nsub+1] (0 element unused) */ char *offp; /* offsets work from here */ char *beginp; /* start of string -- virtual NUL precedes */ char *endp; /* end of string -- virtual NUL here */ char *coldp; /* can be no match starting before here */ char **lastpos; /* [nplus+1] */ STATEVARS; states st; /* current states */ states fresh; /* states for a fresh start */ states tmp; /* temporary */ states empty; /* empty set of states */ }; /* ========= begin header generated by ./mkh ========= */ #ifdef __cplusplus extern "C" { #endif /* === engine.c === */ static int matcher __P((struct re_guts *g, char *string, size_t nmatch, regmatch_t pmatch[], int eflags)); static char *dissect __P((struct match *m, char *start, char *stop, sopno startst, sopno stopst)); static char *backref __P((struct match *m, char *start, char *stop, sopno startst, sopno stopst, sopno lev)); static char *fast __P((struct match *m, char *start, char *stop, sopno startst, sopno stopst)); static char *slow __P((struct match *m, char *start, char *stop, sopno startst, sopno stopst)); static states step __P((struct re_guts *g, sopno start, sopno stop, states bef, int ch, states aft)); #define BOL (OUT+1) #define EOL (BOL+1) #define BOLEOL (BOL+2) #define NOTHING (BOL+3) #define BOW (BOL+4) #define EOW (BOL+5) #define CODEMAX (BOL+5) /* highest code used */ #define NONCHAR(c) ((c) > CHAR_MAX) #define NNONCHAR (CODEMAX-CHAR_MAX) #ifdef REDEBUG static void print __P((struct match *m, char *caption, states st, int ch, FILE *d)); #endif #ifdef REDEBUG static void at __P((struct match *m, char *title, char *start, char *stop, sopno startst, sopno stopst)); #endif #ifdef REDEBUG static char *pchar __P((int ch)); #endif #ifdef __cplusplus } #endif /* ========= end header generated by ./mkh ========= */ #ifdef REDEBUG #define SP(t, s, c) print(m, t, s, c, stdout) #define AT(t, p1, p2, s1, s2) at(m, t, p1, p2, s1, s2) #define NOTE(str) { if (m->eflags®_TRACE) (void)printf("=%s\n", (str)); } #else #define SP(t, s, c) /* nothing */ #define AT(t, p1, p2, s1, s2) /* nothing */ #define NOTE(s) /* nothing */ #endif /* - matcher - the actual matching engine == static int matcher(register struct re_guts *g, char *string, \ == size_t nmatch, regmatch_t pmatch[], int eflags); */ static int /* 0 success, REG_NOMATCH failure */ matcher(g, string, nmatch, pmatch, eflags) register struct re_guts *g; char *string; size_t nmatch; regmatch_t pmatch[]; int eflags; { register char *endp; register int i; struct match mv; register struct match *m = &mv; register char *dp; const register sopno gf = g->firststate+1; /* +1 for OEND */ const register sopno gl = g->laststate; char *start; char *stop; /* simplify the situation where possible */ if (g->cflags®_NOSUB) nmatch = 0; if (eflags®_STARTEND) { start = string + pmatch[0].rm_so; stop = string + pmatch[0].rm_eo; } else { start = string; stop = start + strlen(start); } if (stop < start) return(REG_INVARG); /* prescreening; this does wonders for this rather slow code */ if (g->must != NULL) { for (dp = start; dp < stop; dp++) if (*dp == g->must[0] && stop - dp >= g->mlen && memcmp(dp, g->must, (size_t)g->mlen) == 0) break; if (dp == stop) /* we didn't find g->must */ return(REG_NOMATCH); } /* match struct setup */ m->g = g; m->eflags = eflags; m->pmatch = NULL; m->lastpos = NULL; m->offp = string; m->beginp = start; m->endp = stop; STATESETUP(m, 4); SETUP(m->st); SETUP(m->fresh); SETUP(m->tmp); SETUP(m->empty); CLEAR(m->empty); /* this loop does only one repetition except for backrefs */ for (;;) { endp = fast(m, start, stop, gf, gl); if (endp == NULL) { /* a miss */ STATETEARDOWN(m); return(REG_NOMATCH); } if (nmatch == 0 && !g->backrefs) break; /* no further info needed */ /* where? */ assert(m->coldp != NULL); for (;;) { NOTE("finding start"); endp = slow(m, m->coldp, stop, gf, gl); if (endp != NULL) break; assert(m->coldp < m->endp); m->coldp++; } if (nmatch == 1 && !g->backrefs) break; /* no further info needed */ /* oh my, he wants the subexpressions... */ if (m->pmatch == NULL) m->pmatch = (regmatch_t *)malloc((m->g->nsub + 1) * sizeof(regmatch_t)); if (m->pmatch == NULL) { STATETEARDOWN(m); return(REG_ESPACE); } for (i = 1; i <= m->g->nsub; i++) m->pmatch[i].rm_so = m->pmatch[i].rm_eo = -1; if (!g->backrefs && !(m->eflags®_BACKR)) { NOTE("dissecting"); dp = dissect(m, m->coldp, endp, gf, gl); } else { if (g->nplus > 0 && m->lastpos == NULL) m->lastpos = (char **)malloc((g->nplus+1) * sizeof(char *)); if (g->nplus > 0 && m->lastpos == NULL) { free(m->pmatch); STATETEARDOWN(m); return(REG_ESPACE); } NOTE("backref dissect"); dp = backref(m, m->coldp, endp, gf, gl, (sopno)0); } if (dp != NULL) break; /* uh-oh... we couldn't find a subexpression-level match */ assert(g->backrefs); /* must be back references doing it */ assert(g->nplus == 0 || m->lastpos != NULL); for (;;) { if (dp != NULL || endp <= m->coldp) break; /* defeat */ NOTE("backoff"); endp = slow(m, m->coldp, endp-1, gf, gl); if (endp == NULL) break; /* defeat */ /* try it on a shorter possibility */ #ifndef NDEBUG for (i = 1; i <= m->g->nsub; i++) { assert(m->pmatch[i].rm_so == -1); assert(m->pmatch[i].rm_eo == -1); } #endif NOTE("backoff dissect"); dp = backref(m, m->coldp, endp, gf, gl, (sopno)0); } assert(dp == NULL || dp == endp); if (dp != NULL) /* found a shorter one */ break; /* despite initial appearances, there is no match here */ NOTE("false alarm"); start = m->coldp + 1; /* recycle starting later */ assert(start <= stop); } /* fill in the details if requested */ if (nmatch > 0) { pmatch[0].rm_so = m->coldp - m->offp; pmatch[0].rm_eo = endp - m->offp; } if (nmatch > 1) { assert(m->pmatch != NULL); for (i = 1; i < nmatch; i++) if (i <= m->g->nsub) pmatch[i] = m->pmatch[i]; else { pmatch[i].rm_so = -1; pmatch[i].rm_eo = -1; } } if (m->pmatch != NULL) free((char *)m->pmatch); if (m->lastpos != NULL) free((char *)m->lastpos); STATETEARDOWN(m); return(0); } /* - dissect - figure out what matched what, no back references == static char *dissect(register struct match *m, char *start, \ == char *stop, sopno startst, sopno stopst); */ static char * /* == stop (success) always */ dissect(m, start, stop, startst, stopst) register struct match *m; char *start; char *stop; sopno startst; sopno stopst; { register int i; register sopno ss; /* start sop of current subRE */ register sopno es; /* end sop of current subRE */ register char *sp; /* start of string matched by it */ register char *stp; /* string matched by it cannot pass here */ register char *rest; /* start of rest of string */ register char *tail; /* string unmatched by rest of RE */ register sopno ssub; /* start sop of subsubRE */ register sopno esub; /* end sop of subsubRE */ register char *ssp; /* start of string matched by subsubRE */ register char *sep; /* end of string matched by subsubRE */ register char *oldssp; /* previous ssp */ register char *dp; AT("diss", start, stop, startst, stopst); sp = start; for (ss = startst; ss < stopst; ss = es) { /* identify end of subRE */ es = ss; switch (OP(m->g->strip[es])) { case OPLUS_: case OQUEST_: es += OPND(m->g->strip[es]); break; case OCH_: while (OP(m->g->strip[es]) != O_CH) es += OPND(m->g->strip[es]); break; } es++; /* figure out what it matched */ switch (OP(m->g->strip[ss])) { case OEND: assert(nope); break; case OCHAR: sp++; break; case OBOL: case OEOL: case OBOW: case OEOW: break; case OANY: case OANYOF: sp++; break; case OBACK_: case O_BACK: assert(nope); break; /* cases where length of match is hard to find */ case OQUEST_: stp = stop; for (;;) { /* how long could this one be? */ rest = slow(m, sp, stp, ss, es); assert(rest != NULL); /* it did match */ /* could the rest match the rest? */ tail = slow(m, rest, stop, es, stopst); if (tail == stop) break; /* yes! */ /* no -- try a shorter match for this one */ stp = rest - 1; assert(stp >= sp); /* it did work */ } ssub = ss + 1; esub = es - 1; /* did innards match? */ if (slow(m, sp, rest, ssub, esub) != NULL) { dp = dissect(m, sp, rest, ssub, esub); assert(dp == rest); } else /* no */ assert(sp == rest); sp = rest; break; case OPLUS_: stp = stop; for (;;) { /* how long could this one be? */ rest = slow(m, sp, stp, ss, es); assert(rest != NULL); /* it did match */ /* could the rest match the rest? */ tail = slow(m, rest, stop, es, stopst); if (tail == stop) break; /* yes! */ /* no -- try a shorter match for this one */ stp = rest - 1; assert(stp >= sp); /* it did work */ } ssub = ss + 1; esub = es - 1; ssp = sp; oldssp = ssp; for (;;) { /* find last match of innards */ sep = slow(m, ssp, rest, ssub, esub); if (sep == NULL || sep == ssp) break; /* failed or matched null */ oldssp = ssp; /* on to next try */ ssp = sep; } if (sep == NULL) { /* last successful match */ sep = ssp; ssp = oldssp; } assert(sep == rest); /* must exhaust substring */ assert(slow(m, ssp, sep, ssub, esub) == rest); dp = dissect(m, ssp, sep, ssub, esub); assert(dp == sep); sp = rest; break; case OCH_: stp = stop; for (;;) { /* how long could this one be? */ rest = slow(m, sp, stp, ss, es); assert(rest != NULL); /* it did match */ /* could the rest match the rest? */ tail = slow(m, rest, stop, es, stopst); if (tail == stop) break; /* yes! */ /* no -- try a shorter match for this one */ stp = rest - 1; assert(stp >= sp); /* it did work */ } ssub = ss + 1; esub = ss + OPND(m->g->strip[ss]) - 1; assert(OP(m->g->strip[esub]) == OOR1); for (;;) { /* find first matching branch */ if (slow(m, sp, rest, ssub, esub) == rest) break; /* it matched all of it */ /* that one missed, try next one */ assert(OP(m->g->strip[esub]) == OOR1); esub++; assert(OP(m->g->strip[esub]) == OOR2); ssub = esub + 1; esub += OPND(m->g->strip[esub]); if (OP(m->g->strip[esub]) == OOR2) esub--; else assert(OP(m->g->strip[esub]) == O_CH); } dp = dissect(m, sp, rest, ssub, esub); assert(dp == rest); sp = rest; break; case O_PLUS: case O_QUEST: case OOR1: case OOR2: case O_CH: assert(nope); break; case OLPAREN: i = OPND(m->g->strip[ss]); assert(0 < i && i <= m->g->nsub); m->pmatch[i].rm_so = sp - m->offp; break; case ORPAREN: i = OPND(m->g->strip[ss]); assert(0 < i && i <= m->g->nsub); m->pmatch[i].rm_eo = sp - m->offp; break; default: /* uh oh */ assert(nope); break; } } assert(sp == stop); return(sp); } /* - backref - figure out what matched what, figuring in back references == static char *backref(register struct match *m, char *start, \ == char *stop, sopno startst, sopno stopst, sopno lev); */ static char * /* == stop (success) or NULL (failure) */ backref(m, start, stop, startst, stopst, lev) register struct match *m; char *start; char *stop; sopno startst; sopno stopst; sopno lev; /* PLUS nesting level */ { register int i; register sopno ss; /* start sop of current subRE */ register char *sp; /* start of string matched by it */ register sopno ssub; /* start sop of subsubRE */ register sopno esub; /* end sop of subsubRE */ register char *ssp; /* start of string matched by subsubRE */ register char *dp; register size_t len; register int hard; register sop s; register regoff_t offsave; register cset *cs; AT("back", start, stop, startst, stopst); sp = start; /* get as far as we can with easy stuff */ hard = 0; for (ss = startst; !hard && ss < stopst; ss++) switch (OP(s = m->g->strip[ss])) { case OCHAR: if (sp == stop || *sp++ != (char)OPND(s)) return(NULL); break; case OANY: if (sp == stop) return(NULL); sp++; break; case OANYOF: cs = &m->g->sets[OPND(s)]; if (sp == stop || !CHIN(cs, *sp++)) return(NULL); break; case OBOL: if ( (sp == m->beginp && !(m->eflags®_NOTBOL)) || (sp < m->endp && *(sp-1) == '\n' && (m->g->cflags®_NEWLINE)) ) { /* yes */ } else return(NULL); break; case OEOL: if ( (sp == m->endp && !(m->eflags®_NOTEOL)) || (sp < m->endp && *sp == '\n' && (m->g->cflags®_NEWLINE)) ) { /* yes */ } else return(NULL); break; case OBOW: if (( (sp == m->beginp && !(m->eflags®_NOTBOL)) || (sp < m->endp && *(sp-1) == '\n' && (m->g->cflags®_NEWLINE)) || (sp > m->beginp && !ISWORD(*(sp-1))) ) && (sp < m->endp && ISWORD(*sp)) ) { /* yes */ } else return(NULL); break; case OEOW: if (( (sp == m->endp && !(m->eflags®_NOTEOL)) || (sp < m->endp && *sp == '\n' && (m->g->cflags®_NEWLINE)) || (sp < m->endp && !ISWORD(*sp)) ) && (sp > m->beginp && ISWORD(*(sp-1))) ) { /* yes */ } else return(NULL); break; case O_QUEST: break; case OOR1: /* matches null but needs to skip */ ss++; s = m->g->strip[ss]; do { assert(OP(s) == OOR2); ss += OPND(s); } while (OP(s = m->g->strip[ss]) != O_CH); /* note that the ss++ gets us past the O_CH */ break; default: /* have to make a choice */ hard = 1; break; } if (!hard) { /* that was it! */ if (sp != stop) return(NULL); return(sp); } ss--; /* adjust for the for's final increment */ /* the hard stuff */ AT("hard", sp, stop, ss, stopst); s = m->g->strip[ss]; switch (OP(s)) { case OBACK_: /* the vilest depths */ i = OPND(s); assert(0 < i && i <= m->g->nsub); if (m->pmatch[i].rm_eo == -1) return(NULL); assert(m->pmatch[i].rm_so != -1); len = m->pmatch[i].rm_eo - m->pmatch[i].rm_so; assert(stop - m->beginp >= len); if (sp > stop - len) return(NULL); /* not enough left to match */ ssp = m->offp + m->pmatch[i].rm_so; if (memcmp(sp, ssp, len) != 0) return(NULL); while (m->g->strip[ss] != SOP(O_BACK, i)) ss++; return(backref(m, sp+len, stop, ss+1, stopst, lev)); break; case OQUEST_: /* to null or not */ dp = backref(m, sp, stop, ss+1, stopst, lev); if (dp != NULL) return(dp); /* not */ return(backref(m, sp, stop, ss+OPND(s)+1, stopst, lev)); break; case OPLUS_: assert(m->lastpos != NULL); assert(lev+1 <= m->g->nplus); m->lastpos[lev+1] = sp; return(backref(m, sp, stop, ss+1, stopst, lev+1)); break; case O_PLUS: if (sp == m->lastpos[lev]) /* last pass matched null */ return(backref(m, sp, stop, ss+1, stopst, lev-1)); /* try another pass */ m->lastpos[lev] = sp; dp = backref(m, sp, stop, ss-OPND(s)+1, stopst, lev); if (dp == NULL) return(backref(m, sp, stop, ss+1, stopst, lev-1)); else return(dp); break; case OCH_: /* find the right one, if any */ ssub = ss + 1; esub = ss + OPND(s) - 1; assert(OP(m->g->strip[esub]) == OOR1); for (;;) { /* find first matching branch */ dp = backref(m, sp, stop, ssub, esub, lev); if (dp != NULL) return(dp); /* that one missed, try next one */ if (OP(m->g->strip[esub]) == O_CH) return(NULL); /* there is none */ esub++; assert(OP(m->g->strip[esub]) == OOR2); ssub = esub + 1; esub += OPND(m->g->strip[esub]); if (OP(m->g->strip[esub]) == OOR2) esub--; else assert(OP(m->g->strip[esub]) == O_CH); } break; case OLPAREN: /* must undo assignment if rest fails */ i = OPND(s); assert(0 < i && i <= m->g->nsub); offsave = m->pmatch[i].rm_so; m->pmatch[i].rm_so = sp - m->offp; dp = backref(m, sp, stop, ss+1, stopst, lev); if (dp != NULL) return(dp); m->pmatch[i].rm_so = offsave; return(NULL); break; case ORPAREN: /* must undo assignment if rest fails */ i = OPND(s); assert(0 < i && i <= m->g->nsub); offsave = m->pmatch[i].rm_eo; m->pmatch[i].rm_eo = sp - m->offp; dp = backref(m, sp, stop, ss+1, stopst, lev); if (dp != NULL) return(dp); m->pmatch[i].rm_eo = offsave; return(NULL); break; default: /* uh oh */ assert(nope); break; } /* "can't happen" */ assert(nope); /* NOTREACHED */ } /* - fast - step through the string at top speed == static char *fast(register struct match *m, char *start, \ == char *stop, sopno startst, sopno stopst); */ static char * /* where tentative match ended, or NULL */ fast(m, start, stop, startst, stopst) register struct match *m; char *start; char *stop; sopno startst; sopno stopst; { register states st = m->st; register states fresh = m->fresh; register states tmp = m->tmp; register char *p = start; register int c = (start == m->beginp) ? OUT : *(start-1); register int lastc; /* previous c */ register int flagch; register int i; register char *coldp; /* last p after which no match was underway */ CLEAR(st); SET1(st, startst); st = step(m->g, startst, stopst, st, NOTHING, st); ASSIGN(fresh, st); SP("start", st, *p); coldp = NULL; for (;;) { /* next character */ lastc = c; c = (p == m->endp) ? OUT : *p; if (EQ(st, fresh)) coldp = p; /* is there an EOL and/or BOL between lastc and c? */ flagch = '\0'; i = 0; if ( (lastc == '\n' && m->g->cflags®_NEWLINE) || (lastc == OUT && !(m->eflags®_NOTBOL)) ) { flagch = BOL; i = m->g->nbol; } if ( (c == '\n' && m->g->cflags®_NEWLINE) || (c == OUT && !(m->eflags®_NOTEOL)) ) { flagch = (flagch == BOL) ? BOLEOL : EOL; i += m->g->neol; } if (i != 0) { for (; i > 0; i--) st = step(m->g, startst, stopst, st, flagch, st); SP("boleol", st, c); } /* how about a word boundary? */ if ( (flagch == BOL || (lastc != OUT && !ISWORD(lastc))) && (c != OUT && ISWORD(c)) ) { flagch = BOW; } if ( (lastc != OUT && ISWORD(lastc)) && (flagch == EOL || (c != OUT && !ISWORD(c))) ) { flagch = EOW; } if (flagch == BOW || flagch == EOW) { st = step(m->g, startst, stopst, st, flagch, st); SP("boweow", st, c); } /* are we done? */ if (ISSET(st, stopst) || p == stop) break; /* NOTE BREAK OUT */ /* no, we must deal with this character */ ASSIGN(tmp, st); ASSIGN(st, fresh); assert(c != OUT); st = step(m->g, startst, stopst, tmp, c, st); SP("aft", st, c); assert(EQ(step(m->g, startst, stopst, st, NOTHING, st), st)); p++; } assert(coldp != NULL); m->coldp = coldp; if (ISSET(st, stopst)) return(p+1); else return(NULL); } /* - slow - step through the string more deliberately == static char *slow(register struct match *m, char *start, \ == char *stop, sopno startst, sopno stopst); */ static char * /* where it ended */ slow(m, start, stop, startst, stopst) register struct match *m; char *start; char *stop; sopno startst; sopno stopst; { register states st = m->st; register states empty = m->empty; register states tmp = m->tmp; register char *p = start; register int c = (start == m->beginp) ? OUT : *(start-1); register int lastc; /* previous c */ register int flagch; register int i; register char *matchp; /* last p at which a match ended */ AT("slow", start, stop, startst, stopst); CLEAR(st); SET1(st, startst); SP("sstart", st, *p); st = step(m->g, startst, stopst, st, NOTHING, st); matchp = NULL; for (;;) { /* next character */ lastc = c; c = (p == m->endp) ? OUT : *p; /* is there an EOL and/or BOL between lastc and c? */ flagch = '\0'; i = 0; if ( (lastc == '\n' && m->g->cflags®_NEWLINE) || (lastc == OUT && !(m->eflags®_NOTBOL)) ) { flagch = BOL; i = m->g->nbol; } if ( (c == '\n' && m->g->cflags®_NEWLINE) || (c == OUT && !(m->eflags®_NOTEOL)) ) { flagch = (flagch == BOL) ? BOLEOL : EOL; i += m->g->neol; } if (i != 0) { for (; i > 0; i--) st = step(m->g, startst, stopst, st, flagch, st); SP("sboleol", st, c); } /* how about a word boundary? */ if ( (flagch == BOL || (lastc != OUT && !ISWORD(lastc))) && (c != OUT && ISWORD(c)) ) { flagch = BOW; } if ( (lastc != OUT && ISWORD(lastc)) && (flagch == EOL || (c != OUT && !ISWORD(c))) ) { flagch = EOW; } if (flagch == BOW || flagch == EOW) { st = step(m->g, startst, stopst, st, flagch, st); SP("sboweow", st, c); } /* are we done? */ if (ISSET(st, stopst)) matchp = p; if (EQ(st, empty) || p == stop) break; /* NOTE BREAK OUT */ /* no, we must deal with this character */ ASSIGN(tmp, st); ASSIGN(st, empty); assert(c != OUT); st = step(m->g, startst, stopst, tmp, c, st); SP("saft", st, c); assert(EQ(step(m->g, startst, stopst, st, NOTHING, st), st)); p++; } return(matchp); } /* - step - map set of states reachable before char to set reachable after == static states step(register struct re_guts *g, sopno start, sopno stop, \ == register states bef, int ch, register states aft); == #define BOL (OUT+1) == #define EOL (BOL+1) == #define BOLEOL (BOL+2) == #define NOTHING (BOL+3) == #define BOW (BOL+4) == #define EOW (BOL+5) == #define CODEMAX (BOL+5) // highest code used == #define NONCHAR(c) ((c) > CHAR_MAX) == #define NNONCHAR (CODEMAX-CHAR_MAX) */ static states step(g, start, stop, bef, ch, aft) register struct re_guts *g; sopno start; /* start state within strip */ sopno stop; /* state after stop state within strip */ register states bef; /* states reachable before */ int ch; /* character or NONCHAR code */ register states aft; /* states already known reachable after */ { register cset *cs; register sop s; register sopno pc; register onestate here; /* note, macros know this name */ register sopno look; register int i; for (pc = start, INIT(here, pc); pc != stop; pc++, INC(here)) { s = g->strip[pc]; switch (OP(s)) { case OEND: assert(pc == stop-1); break; case OCHAR: /* only characters can match */ assert(!NONCHAR(ch) || ch != (char)OPND(s)); if (ch == (char)OPND(s)) FWD(aft, bef, 1); break; case OBOL: if (ch == BOL || ch == BOLEOL) FWD(aft, bef, 1); break; case OEOL: if (ch == EOL || ch == BOLEOL) FWD(aft, bef, 1); break; case OBOW: if (ch == BOW) FWD(aft, bef, 1); break; case OEOW: if (ch == EOW) FWD(aft, bef, 1); break; case OANY: if (!NONCHAR(ch)) FWD(aft, bef, 1); break; case OANYOF: cs = &g->sets[OPND(s)]; if (!NONCHAR(ch) && CHIN(cs, ch)) FWD(aft, bef, 1); break; case OBACK_: /* ignored here */ case O_BACK: FWD(aft, aft, 1); break; case OPLUS_: /* forward, this is just an empty */ FWD(aft, aft, 1); break; case O_PLUS: /* both forward and back */ FWD(aft, aft, 1); i = ISSETBACK(aft, OPND(s)); BACK(aft, aft, OPND(s)); if (!i && ISSETBACK(aft, OPND(s))) { /* oho, must reconsider loop body */ pc -= OPND(s) + 1; INIT(here, pc); } break; case OQUEST_: /* two branches, both forward */ FWD(aft, aft, 1); FWD(aft, aft, OPND(s)); break; case O_QUEST: /* just an empty */ FWD(aft, aft, 1); break; case OLPAREN: /* not significant here */ case ORPAREN: FWD(aft, aft, 1); break; case OCH_: /* mark the first two branches */ FWD(aft, aft, 1); assert(OP(g->strip[pc+OPND(s)]) == OOR2); FWD(aft, aft, OPND(s)); break; case OOR1: /* done a branch, find the O_CH */ if (ISSTATEIN(aft, here)) { for (look = 1; OP(s = g->strip[pc+look]) != O_CH; look += OPND(s)) assert(OP(s) == OOR2); FWD(aft, aft, look); } break; case OOR2: /* propagate OCH_'s marking */ FWD(aft, aft, 1); if (OP(g->strip[pc+OPND(s)]) != O_CH) { assert(OP(g->strip[pc+OPND(s)]) == OOR2); FWD(aft, aft, OPND(s)); } break; case O_CH: /* just empty */ FWD(aft, aft, 1); break; default: /* ooooops... */ assert(nope); break; } } return(aft); } #ifdef REDEBUG /* - print - print a set of states == #ifdef REDEBUG == static void print(struct match *m, char *caption, states st, \ == int ch, FILE *d); == #endif */ static void print(m, caption, st, ch, d) struct match *m; char *caption; states st; int ch; FILE *d; { register struct re_guts *g = m->g; register int i; register int first = 1; if (!(m->eflags®_TRACE)) return; (void)fprintf(d, "%s", caption); if (ch != '\0') (void)fprintf(d, " %s", pchar(ch)); for (i = 0; i < g->nstates; i++) if (ISSET(st, i)) { (void)fprintf(d, "%s%d", (first) ? "\t" : ", ", i); first = 0; } (void)fprintf(d, "\n"); } /* - at - print current situation == #ifdef REDEBUG == static void at(struct match *m, char *title, char *start, char *stop, \ == sopno startst, sopno stopst); == #endif */ static void at(m, title, start, stop, startst, stopst) struct match *m; char *title; char *start; char *stop; sopno startst; sopno stopst; { if (!(m->eflags®_TRACE)) return; (void)printf("%s %s-", title, pchar(*start)); (void)printf("%s ", pchar(*stop)); (void)printf("%ld-%ld\n", (long)startst, (long)stopst); } #ifndef PCHARDONE #define PCHARDONE /* never again */ /* - pchar - make a character printable == #ifdef REDEBUG == static char *pchar(int ch); == #endif * * Is this identical to regchar() over in debug.c? Well, yes. But a * duplicate here avoids having a debugging-capable regexec.o tied to * a matching debug.o, and this is convenient. It all disappears in * the non-debug compilation anyway, so it doesn't matter much. */ static char * /* -> representation */ pchar(ch) int ch; { static char pbuf[10]; if (isprint(ch) || ch == ' ') (void)sprintf(pbuf, "%c", ch); else (void)sprintf(pbuf, "\\%o", ch); return(pbuf); } #endif #endif #undef matcher #undef fast #undef slow #undef dissect #undef backref #undef step #undef print #undef at #undef match sma-1.4.orig/regex/regcomp.c0000644000175000017500000011711007603333515016207 0ustar apollockapollock/*- * Copyright (c) 1992, 1993, 1994 Henry Spencer. * Copyright (c) 1992, 1993, 1994 * The Regents of the University of California. All rights reserved. * * This code is derived from software contributed to Berkeley by * Henry Spencer. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * @(#)regcomp.c 8.5 (Berkeley) 3/20/94 */ #include #include #include #include #include #include #include "regex.h" #include "utils.h" #include "regex2.h" #include "cclass.h" #include "cname.h" /* * parse structure, passed up and down to avoid global variables and * other clumsinesses */ struct parse { char *next; /* next character in RE */ char *end; /* end of string (-> NUL normally) */ int error; /* has an error been seen? */ sop *strip; /* malloced strip */ sopno ssize; /* malloced strip size (allocated) */ sopno slen; /* malloced strip length (used) */ int ncsalloc; /* number of csets allocated */ struct re_guts *g; # define NPAREN 10 /* we need to remember () 1-9 for back refs */ sopno pbegin[NPAREN]; /* -> ( ([0] unused) */ sopno pend[NPAREN]; /* -> ) ([0] unused) */ }; /* ========= begin header generated by ./mkh ========= */ #ifdef __cplusplus extern "C" { #endif /* === regcomp.c === */ static void p_ere __P((struct parse *p, int stop)); static void p_ere_exp __P((struct parse *p)); static void p_str __P((struct parse *p)); static void p_bre __P((struct parse *p, int end1, int end2)); static int p_simp_re __P((struct parse *p, int starordinary)); static int p_count __P((struct parse *p)); static void p_bracket __P((struct parse *p)); static void p_b_term __P((struct parse *p, cset *cs)); static void p_b_cclass __P((struct parse *p, cset *cs)); static void p_b_eclass __P((struct parse *p, cset *cs)); static char p_b_symbol __P((struct parse *p)); static char p_b_coll_elem __P((struct parse *p, int endc)); static char othercase __P((int ch)); static void bothcases __P((struct parse *p, int ch)); static void ordinary __P((struct parse *p, int ch)); static void nonnewline __P((struct parse *p)); static void repeat __P((struct parse *p, sopno start, int from, int to)); static int seterr __P((struct parse *p, int e)); static cset *allocset __P((struct parse *p)); static void freeset __P((struct parse *p, cset *cs)); static int freezeset __P((struct parse *p, cset *cs)); static int firstch __P((struct parse *p, cset *cs)); static int nch __P((struct parse *p, cset *cs)); static void mcadd __P((struct parse *p, cset *cs, char *cp)); static void mcinvert __P((struct parse *p, cset *cs)); static void mccase __P((struct parse *p, cset *cs)); static int isinsets __P((struct re_guts *g, int c)); static int samesets __P((struct re_guts *g, int c1, int c2)); static void categorize __P((struct parse *p, struct re_guts *g)); static sopno dupl __P((struct parse *p, sopno start, sopno finish)); static void doemit __P((struct parse *p, sop op, size_t opnd)); static void doinsert __P((struct parse *p, sop op, size_t opnd, sopno pos)); static void dofwd __P((struct parse *p, sopno pos, sop value)); static void enlarge __P((struct parse *p, sopno size)); static void stripsnug __P((struct parse *p, struct re_guts *g)); static void findmust __P((struct parse *p, struct re_guts *g)); static sopno pluscount __P((struct parse *p, struct re_guts *g)); #ifdef __cplusplus } #endif /* ========= end header generated by ./mkh ========= */ static char nuls[10]; /* place to point scanner in event of error */ /* * macros for use with parse structure * BEWARE: these know that the parse structure is named `p' !!! */ #define PEEK() (*p->next) #define PEEK2() (*(p->next+1)) #define MORE() (p->next < p->end) #define MORE2() (p->next+1 < p->end) #define SEE(c) (MORE() && PEEK() == (c)) #define SEETWO(a, b) (MORE() && MORE2() && PEEK() == (a) && PEEK2() == (b)) #define EAT(c) ((SEE(c)) ? (NEXT(), 1) : 0) #define EATTWO(a, b) ((SEETWO(a, b)) ? (NEXT2(), 1) : 0) #define NEXT() (p->next++) #define NEXT2() (p->next += 2) #define NEXTn(n) (p->next += (n)) #define GETNEXT() (*p->next++) #define SETERROR(e) seterr(p, (e)) #define REQUIRE(co, e) ((co) || SETERROR(e)) #define MUSTSEE(c, e) (REQUIRE(MORE() && PEEK() == (c), e)) #define MUSTEAT(c, e) (REQUIRE(MORE() && GETNEXT() == (c), e)) #define MUSTNOTSEE(c, e) (REQUIRE(!MORE() || PEEK() != (c), e)) #define EMIT(op, sopnd) doemit(p, (sop)(op), (size_t)(sopnd)) #define INSERT(op, pos) doinsert(p, (sop)(op), HERE()-(pos)+1, pos) #define AHEAD(pos) dofwd(p, pos, HERE()-(pos)) #define ASTERN(sop, pos) EMIT(sop, HERE()-pos) #define HERE() (p->slen) #define THERE() (p->slen - 1) #define THERETHERE() (p->slen - 2) #define DROP(n) (p->slen -= (n)) #ifndef NDEBUG static int never = 0; /* for use in asserts; shuts lint up */ #else #define never 0 /* some s have bugs too */ #endif /* - regcomp - interface for parser and compilation = extern int regcomp(regex_t *, const char *, int); = #define REG_BASIC 0000 = #define REG_EXTENDED 0001 = #define REG_ICASE 0002 = #define REG_NOSUB 0004 = #define REG_NEWLINE 0010 = #define REG_NOSPEC 0020 = #define REG_PEND 0040 = #define REG_DUMP 0200 */ int /* 0 success, otherwise REG_something */ regcomp(preg, pattern, cflags) regex_t *preg; const char *pattern; int cflags; { struct parse pa; register struct re_guts *g; register struct parse *p = &pa; register int i; register size_t len; #ifdef REDEBUG # define GOODFLAGS(f) (f) #else # define GOODFLAGS(f) ((f)&~REG_DUMP) #endif cflags = GOODFLAGS(cflags); if ((cflags®_EXTENDED) && (cflags®_NOSPEC)) return(REG_INVARG); if (cflags®_PEND) { if (preg->re_endp < pattern) return(REG_INVARG); len = preg->re_endp - pattern; } else len = strlen((char *)pattern); /* do the mallocs early so failure handling is easy */ g = (struct re_guts *)malloc(sizeof(struct re_guts) + (NC-1)*sizeof(cat_t)); if (g == NULL) return(REG_ESPACE); p->ssize = len/(size_t)2*(size_t)3 + (size_t)1; /* ugh */ p->strip = (sop *)malloc(p->ssize * sizeof(sop)); p->slen = 0; if (p->strip == NULL) { free((char *)g); return(REG_ESPACE); } /* set things up */ p->g = g; p->next = (char *)pattern; /* convenience; we do not modify it */ p->end = p->next + len; p->error = 0; p->ncsalloc = 0; for (i = 0; i < NPAREN; i++) { p->pbegin[i] = 0; p->pend[i] = 0; } g->csetsize = NC; g->sets = NULL; g->setbits = NULL; g->ncsets = 0; g->cflags = cflags; g->iflags = 0; g->nbol = 0; g->neol = 0; g->must = NULL; g->mlen = 0; g->nsub = 0; g->ncategories = 1; /* category 0 is "everything else" */ g->categories = &g->catspace[-(CHAR_MIN)]; (void) memset((char *)g->catspace, 0, NC*sizeof(cat_t)); g->backrefs = 0; /* do it */ EMIT(OEND, 0); g->firststate = THERE(); if (cflags®_EXTENDED) p_ere(p, OUT); else if (cflags®_NOSPEC) p_str(p); else p_bre(p, OUT, OUT); EMIT(OEND, 0); g->laststate = THERE(); /* tidy up loose ends and fill things in */ categorize(p, g); stripsnug(p, g); findmust(p, g); g->nplus = pluscount(p, g); g->magic = MAGIC2; preg->re_nsub = g->nsub; preg->re_g = g; preg->re_magic = MAGIC1; #ifndef REDEBUG /* not debugging, so can't rely on the assert() in regexec() */ if (g->iflags&BAD) SETERROR(REG_ASSERT); #endif /* win or lose, we're done */ if (p->error != 0) /* lose */ regfree(preg); return(p->error); } /* - p_ere - ERE parser top level, concatenation and alternation == static void p_ere(register struct parse *p, int stop); */ static void p_ere(p, stop) register struct parse *p; int stop; /* character this ERE should end at */ { register char c; register sopno prevback; register sopno prevfwd; register sopno conc; register int first = 1; /* is this the first alternative? */ for (;;) { /* do a bunch of concatenated expressions */ conc = HERE(); while (MORE() && (c = PEEK()) != '|' && c != stop) p_ere_exp(p); REQUIRE(HERE() != conc, REG_EMPTY); /* require nonempty */ if (!EAT('|')) break; /* NOTE BREAK OUT */ if (first) { INSERT(OCH_, conc); /* offset is wrong */ prevfwd = conc; prevback = conc; first = 0; } ASTERN(OOR1, prevback); prevback = THERE(); AHEAD(prevfwd); /* fix previous offset */ prevfwd = HERE(); EMIT(OOR2, 0); /* offset is very wrong */ } if (!first) { /* tail-end fixups */ AHEAD(prevfwd); ASTERN(O_CH, prevback); } assert(!MORE() || SEE(stop)); } /* - p_ere_exp - parse one subERE, an atom possibly followed by a repetition op == static void p_ere_exp(register struct parse *p); */ static void p_ere_exp(p) register struct parse *p; { register char c; register sopno pos; register int count; register int count2; register sopno subno; int wascaret = 0; assert(MORE()); /* caller should have ensured this */ c = GETNEXT(); pos = HERE(); switch (c) { case '(': REQUIRE(MORE(), REG_EPAREN); p->g->nsub++; subno = p->g->nsub; if (subno < NPAREN) p->pbegin[subno] = HERE(); EMIT(OLPAREN, subno); if (!SEE(')')) p_ere(p, ')'); if (subno < NPAREN) { p->pend[subno] = HERE(); assert(p->pend[subno] != 0); } EMIT(ORPAREN, subno); MUSTEAT(')', REG_EPAREN); break; #ifndef POSIX_MISTAKE case ')': /* happens only if no current unmatched ( */ /* * You may ask, why the ifndef? Because I didn't notice * this until slightly too late for 1003.2, and none of the * other 1003.2 regular-expression reviewers noticed it at * all. So an unmatched ) is legal POSIX, at least until * we can get it fixed. */ SETERROR(REG_EPAREN); break; #endif case '^': EMIT(OBOL, 0); p->g->iflags |= USEBOL; p->g->nbol++; wascaret = 1; break; case '$': EMIT(OEOL, 0); p->g->iflags |= USEEOL; p->g->neol++; break; case '|': SETERROR(REG_EMPTY); break; case '*': case '+': case '?': SETERROR(REG_BADRPT); break; case '.': if (p->g->cflags®_NEWLINE) nonnewline(p); else EMIT(OANY, 0); break; case '[': p_bracket(p); break; case '\\': REQUIRE(MORE(), REG_EESCAPE); c = GETNEXT(); ordinary(p, c); break; case '{': /* okay as ordinary except if digit follows */ REQUIRE(!MORE() || !isdigit(PEEK()), REG_BADRPT); /* FALLTHROUGH */ default: ordinary(p, c); break; } if (!MORE()) return; c = PEEK(); /* we call { a repetition if followed by a digit */ if (!( c == '*' || c == '+' || c == '?' || (c == '{' && MORE2() && isdigit(PEEK2())) )) return; /* no repetition, we're done */ NEXT(); REQUIRE(!wascaret, REG_BADRPT); switch (c) { case '*': /* implemented as +? */ /* this case does not require the (y|) trick, noKLUDGE */ INSERT(OPLUS_, pos); ASTERN(O_PLUS, pos); INSERT(OQUEST_, pos); ASTERN(O_QUEST, pos); break; case '+': INSERT(OPLUS_, pos); ASTERN(O_PLUS, pos); break; case '?': /* KLUDGE: emit y? as (y|) until subtle bug gets fixed */ INSERT(OCH_, pos); /* offset slightly wrong */ ASTERN(OOR1, pos); /* this one's right */ AHEAD(pos); /* fix the OCH_ */ EMIT(OOR2, 0); /* offset very wrong... */ AHEAD(THERE()); /* ...so fix it */ ASTERN(O_CH, THERETHERE()); break; case '{': count = p_count(p); if (EAT(',')) { if (isdigit(PEEK())) { count2 = p_count(p); REQUIRE(count <= count2, REG_BADBR); } else /* single number with comma */ count2 = INFINITY; } else /* just a single number */ count2 = count; repeat(p, pos, count, count2); if (!EAT('}')) { /* error heuristics */ while (MORE() && PEEK() != '}') NEXT(); REQUIRE(MORE(), REG_EBRACE); SETERROR(REG_BADBR); } break; } if (!MORE()) return; c = PEEK(); if (!( c == '*' || c == '+' || c == '?' || (c == '{' && MORE2() && isdigit(PEEK2())) ) ) return; SETERROR(REG_BADRPT); } /* - p_str - string (no metacharacters) "parser" == static void p_str(register struct parse *p); */ static void p_str(p) register struct parse *p; { REQUIRE(MORE(), REG_EMPTY); while (MORE()) ordinary(p, GETNEXT()); } /* - p_bre - BRE parser top level, anchoring and concatenation == static void p_bre(register struct parse *p, register int end1, \ == register int end2); * Giving end1 as OUT essentially eliminates the end1/end2 check. * * This implementation is a bit of a kludge, in that a trailing $ is first * taken as an ordinary character and then revised to be an anchor. The * only undesirable side effect is that '$' gets included as a character * category in such cases. This is fairly harmless; not worth fixing. * The amount of lookahead needed to avoid this kludge is excessive. */ static void p_bre(p, end1, end2) register struct parse *p; register int end1; /* first terminating character */ register int end2; /* second terminating character */ { register sopno start = HERE(); register int first = 1; /* first subexpression? */ register int wasdollar = 0; if (EAT('^')) { EMIT(OBOL, 0); p->g->iflags |= USEBOL; p->g->nbol++; } while (MORE() && !SEETWO(end1, end2)) { wasdollar = p_simp_re(p, first); first = 0; } if (wasdollar) { /* oops, that was a trailing anchor */ DROP(1); EMIT(OEOL, 0); p->g->iflags |= USEEOL; p->g->neol++; } REQUIRE(HERE() != start, REG_EMPTY); /* require nonempty */ } /* - p_simp_re - parse a simple RE, an atom possibly followed by a repetition == static int p_simp_re(register struct parse *p, int starordinary); */ static int /* was the simple RE an unbackslashed $? */ p_simp_re(p, starordinary) register struct parse *p; int starordinary; /* is a leading * an ordinary character? */ { register int c; register int count; register int count2; register sopno pos; register int i; register sopno subno; # define BACKSL (1<g->cflags®_NEWLINE) nonnewline(p); else EMIT(OANY, 0); break; case '[': p_bracket(p); break; case BACKSL|'{': SETERROR(REG_BADRPT); break; case BACKSL|'(': p->g->nsub++; subno = p->g->nsub; if (subno < NPAREN) p->pbegin[subno] = HERE(); EMIT(OLPAREN, subno); /* the MORE here is an error heuristic */ if (MORE() && !SEETWO('\\', ')')) p_bre(p, '\\', ')'); if (subno < NPAREN) { p->pend[subno] = HERE(); assert(p->pend[subno] != 0); } EMIT(ORPAREN, subno); REQUIRE(EATTWO('\\', ')'), REG_EPAREN); break; case BACKSL|')': /* should not get here -- must be user */ case BACKSL|'}': SETERROR(REG_EPAREN); break; case BACKSL|'1': case BACKSL|'2': case BACKSL|'3': case BACKSL|'4': case BACKSL|'5': case BACKSL|'6': case BACKSL|'7': case BACKSL|'8': case BACKSL|'9': i = (c&~BACKSL) - '0'; assert(i < NPAREN); if (p->pend[i] != 0) { assert(i <= p->g->nsub); EMIT(OBACK_, i); assert(p->pbegin[i] != 0); assert(OP(p->strip[p->pbegin[i]]) == OLPAREN); assert(OP(p->strip[p->pend[i]]) == ORPAREN); (void) dupl(p, p->pbegin[i]+1, p->pend[i]); EMIT(O_BACK, i); } else SETERROR(REG_ESUBREG); p->g->backrefs = 1; break; case '*': REQUIRE(starordinary, REG_BADRPT); /* FALLTHROUGH */ default: ordinary(p, c &~ BACKSL); break; } if (EAT('*')) { /* implemented as +? */ /* this case does not require the (y|) trick, noKLUDGE */ INSERT(OPLUS_, pos); ASTERN(O_PLUS, pos); INSERT(OQUEST_, pos); ASTERN(O_QUEST, pos); } else if (EATTWO('\\', '{')) { count = p_count(p); if (EAT(',')) { if (MORE() && isdigit(PEEK())) { count2 = p_count(p); REQUIRE(count <= count2, REG_BADBR); } else /* single number with comma */ count2 = INFINITY; } else /* just a single number */ count2 = count; repeat(p, pos, count, count2); if (!EATTWO('\\', '}')) { /* error heuristics */ while (MORE() && !SEETWO('\\', '}')) NEXT(); REQUIRE(MORE(), REG_EBRACE); SETERROR(REG_BADBR); } } else if (c == (unsigned char)'$') /* $ (but not \$) ends it */ return(1); return(0); } /* - p_count - parse a repetition count == static int p_count(register struct parse *p); */ static int /* the value */ p_count(p) register struct parse *p; { register int count = 0; register int ndigits = 0; while (MORE() && isdigit(PEEK()) && count <= DUPMAX) { count = count*10 + (GETNEXT() - '0'); ndigits++; } REQUIRE(ndigits > 0 && count <= DUPMAX, REG_BADBR); return(count); } /* - p_bracket - parse a bracketed character list == static void p_bracket(register struct parse *p); * * Note a significant property of this code: if the allocset() did SETERROR, * no set operations are done. */ static void p_bracket(p) register struct parse *p; { register cset *cs = allocset(p); register int invert = 0; /* Dept of Truly Sickening Special-Case Kludges */ if (p->next + 5 < p->end && strncmp(p->next, "[:<:]]", 6) == 0) { EMIT(OBOW, 0); NEXTn(6); return; } if (p->next + 5 < p->end && strncmp(p->next, "[:>:]]", 6) == 0) { EMIT(OEOW, 0); NEXTn(6); return; } if (EAT('^')) invert++; /* make note to invert set at end */ if (EAT(']')) CHadd(cs, ']'); else if (EAT('-')) CHadd(cs, '-'); while (MORE() && PEEK() != ']' && !SEETWO('-', ']')) p_b_term(p, cs); if (EAT('-')) CHadd(cs, '-'); MUSTEAT(']', REG_EBRACK); if (p->error != 0) /* don't mess things up further */ return; if (p->g->cflags®_ICASE) { register int i; register int ci; for (i = p->g->csetsize - 1; i >= 0; i--) if (CHIN(cs, i) && isalpha(i)) { ci = othercase(i); if (ci != i) CHadd(cs, ci); } if (cs->multis != NULL) mccase(p, cs); } if (invert) { register int i; for (i = p->g->csetsize - 1; i >= 0; i--) if (CHIN(cs, i)) CHsub(cs, i); else CHadd(cs, i); if (p->g->cflags®_NEWLINE) CHsub(cs, '\n'); if (cs->multis != NULL) mcinvert(p, cs); } assert(cs->multis == NULL); /* xxx */ if (nch(p, cs) == 1) { /* optimize singleton sets */ ordinary(p, firstch(p, cs)); freeset(p, cs); } else EMIT(OANYOF, freezeset(p, cs)); } /* - p_b_term - parse one term of a bracketed character list == static void p_b_term(register struct parse *p, register cset *cs); */ static void p_b_term(p, cs) register struct parse *p; register cset *cs; { register char c; register char start, finish; register int i; /* classify what we've got */ switch ((MORE()) ? PEEK() : '\0') { case '[': c = (MORE2()) ? PEEK2() : '\0'; break; case '-': SETERROR(REG_ERANGE); return; /* NOTE RETURN */ break; default: c = '\0'; break; } switch (c) { case ':': /* character class */ NEXT2(); REQUIRE(MORE(), REG_EBRACK); c = PEEK(); REQUIRE(c != '-' && c != ']', REG_ECTYPE); p_b_cclass(p, cs); REQUIRE(MORE(), REG_EBRACK); REQUIRE(EATTWO(':', ']'), REG_ECTYPE); break; case '=': /* equivalence class */ NEXT2(); REQUIRE(MORE(), REG_EBRACK); c = PEEK(); REQUIRE(c != '-' && c != ']', REG_ECOLLATE); p_b_eclass(p, cs); REQUIRE(MORE(), REG_EBRACK); REQUIRE(EATTWO('=', ']'), REG_ECOLLATE); break; default: /* symbol, ordinary character, or range */ /* xxx revision needed for multichar stuff */ start = p_b_symbol(p); if (SEE('-') && MORE2() && PEEK2() != ']') { /* range */ NEXT(); if (EAT('-')) finish = '-'; else finish = p_b_symbol(p); } else finish = start; /* xxx what about signed chars here... */ REQUIRE(start <= finish, REG_ERANGE); for (i = start; i <= finish; i++) CHadd(cs, i); break; } } /* - p_b_cclass - parse a character-class name and deal with it == static void p_b_cclass(register struct parse *p, register cset *cs); */ static void p_b_cclass(p, cs) register struct parse *p; register cset *cs; { register char *sp = p->next; register struct cclass *cp; register size_t len; register char *u; register char c; while (MORE() && isalpha(PEEK())) NEXT(); len = p->next - sp; for (cp = cclasses; cp->name != NULL; cp++) if (strncmp(cp->name, sp, len) == 0 && cp->name[len] == '\0') break; if (cp->name == NULL) { /* oops, didn't find it */ SETERROR(REG_ECTYPE); return; } u = cp->chars; while ((c = *u++) != '\0') CHadd(cs, c); for (u = cp->multis; *u != '\0'; u += strlen(u) + 1) MCadd(p, cs, u); } /* - p_b_eclass - parse an equivalence-class name and deal with it == static void p_b_eclass(register struct parse *p, register cset *cs); * * This implementation is incomplete. xxx */ static void p_b_eclass(p, cs) register struct parse *p; register cset *cs; { register char c; c = p_b_coll_elem(p, '='); CHadd(cs, c); } /* - p_b_symbol - parse a character or [..]ed multicharacter collating symbol == static char p_b_symbol(register struct parse *p); */ static char /* value of symbol */ p_b_symbol(p) register struct parse *p; { register char value; REQUIRE(MORE(), REG_EBRACK); if (!EATTWO('[', '.')) return(GETNEXT()); /* collating symbol */ value = p_b_coll_elem(p, '.'); REQUIRE(EATTWO('.', ']'), REG_ECOLLATE); return(value); } /* - p_b_coll_elem - parse a collating-element name and look it up == static char p_b_coll_elem(register struct parse *p, int endc); */ static char /* value of collating element */ p_b_coll_elem(p, endc) register struct parse *p; int endc; /* name ended by endc,']' */ { register char *sp = p->next; register struct cname *cp; register int len; while (MORE() && !SEETWO(endc, ']')) NEXT(); if (!MORE()) { SETERROR(REG_EBRACK); return(0); } len = p->next - sp; for (cp = cnames; cp->name != NULL; cp++) if (strncmp(cp->name, sp, len) == 0 && cp->name[len] == '\0') return(cp->code); /* known name */ if (len == 1) return(*sp); /* single character */ SETERROR(REG_ECOLLATE); /* neither */ return(0); } /* - othercase - return the case counterpart of an alphabetic == static char othercase(int ch); */ static char /* if no counterpart, return ch */ othercase(ch) int ch; { assert(isalpha(ch)); if (isupper(ch)) return(tolower(ch)); else if (islower(ch)) return(toupper(ch)); else /* peculiar, but could happen */ return(ch); } /* - bothcases - emit a dualcase version of a two-case character == static void bothcases(register struct parse *p, int ch); * * Boy, is this implementation ever a kludge... */ static void bothcases(p, ch) register struct parse *p; int ch; { register char *oldnext = p->next; register char *oldend = p->end; char bracket[3]; assert(othercase(ch) != ch); /* p_bracket() would recurse */ p->next = bracket; p->end = bracket+2; bracket[0] = ch; bracket[1] = ']'; bracket[2] = '\0'; p_bracket(p); assert(p->next == bracket+2); p->next = oldnext; p->end = oldend; } /* - ordinary - emit an ordinary character == static void ordinary(register struct parse *p, register int ch); */ static void ordinary(p, ch) register struct parse *p; register int ch; { register cat_t *cap = p->g->categories; if ((p->g->cflags®_ICASE) && isalpha(ch) && othercase(ch) != ch) bothcases(p, ch); else { EMIT(OCHAR, (unsigned char)ch); if (cap[ch] == 0) cap[ch] = p->g->ncategories++; } } /* - nonnewline - emit REG_NEWLINE version of OANY == static void nonnewline(register struct parse *p); * * Boy, is this implementation ever a kludge... */ static void nonnewline(p) register struct parse *p; { register char *oldnext = p->next; register char *oldend = p->end; char bracket[4]; p->next = bracket; p->end = bracket+3; bracket[0] = '^'; bracket[1] = '\n'; bracket[2] = ']'; bracket[3] = '\0'; p_bracket(p); assert(p->next == bracket+3); p->next = oldnext; p->end = oldend; } /* - repeat - generate code for a bounded repetition, recursively if needed == static void repeat(register struct parse *p, sopno start, int from, int to); */ static void repeat(p, start, from, to) register struct parse *p; sopno start; /* operand from here to end of strip */ int from; /* repeated from this number */ int to; /* to this number of times (maybe INFINITY) */ { register sopno finish = HERE(); # define N 2 # define INF 3 # define REP(f, t) ((f)*8 + (t)) # define MAP(n) (((n) <= 1) ? (n) : ((n) == INFINITY) ? INF : N) register sopno copy; if (p->error != 0) /* head off possible runaway recursion */ return; assert(from <= to); switch (REP(MAP(from), MAP(to))) { case REP(0, 0): /* must be user doing this */ DROP(finish-start); /* drop the operand */ break; case REP(0, 1): /* as x{1,1}? */ case REP(0, N): /* as x{1,n}? */ case REP(0, INF): /* as x{1,}? */ /* KLUDGE: emit y? as (y|) until subtle bug gets fixed */ INSERT(OCH_, start); /* offset is wrong... */ repeat(p, start+1, 1, to); ASTERN(OOR1, start); AHEAD(start); /* ... fix it */ EMIT(OOR2, 0); AHEAD(THERE()); ASTERN(O_CH, THERETHERE()); break; case REP(1, 1): /* trivial case */ /* done */ break; case REP(1, N): /* as x?x{1,n-1} */ /* KLUDGE: emit y? as (y|) until subtle bug gets fixed */ INSERT(OCH_, start); ASTERN(OOR1, start); AHEAD(start); EMIT(OOR2, 0); /* offset very wrong... */ AHEAD(THERE()); /* ...so fix it */ ASTERN(O_CH, THERETHERE()); copy = dupl(p, start+1, finish+1); assert(copy == finish+4); repeat(p, copy, 1, to-1); break; case REP(1, INF): /* as x+ */ INSERT(OPLUS_, start); ASTERN(O_PLUS, start); break; case REP(N, N): /* as xx{m-1,n-1} */ copy = dupl(p, start, finish); repeat(p, copy, from-1, to-1); break; case REP(N, INF): /* as xx{n-1,INF} */ copy = dupl(p, start, finish); repeat(p, copy, from-1, to); break; default: /* "can't happen" */ SETERROR(REG_ASSERT); /* just in case */ break; } } /* - seterr - set an error condition == static int seterr(register struct parse *p, int e); */ static int /* useless but makes type checking happy */ seterr(p, e) register struct parse *p; int e; { if (p->error == 0) /* keep earliest error condition */ p->error = e; p->next = nuls; /* try to bring things to a halt */ p->end = nuls; return(0); /* make the return value well-defined */ } /* - allocset - allocate a set of characters for [] == static cset *allocset(register struct parse *p); */ static cset * allocset(p) register struct parse *p; { register int no = p->g->ncsets++; register size_t nc; register size_t nbytes; register cset *cs; register size_t css = (size_t)p->g->csetsize; register int i; if (no >= p->ncsalloc) { /* need another column of space */ p->ncsalloc += CHAR_BIT; nc = p->ncsalloc; assert(nc % CHAR_BIT == 0); nbytes = nc / CHAR_BIT * css; if (p->g->sets == NULL) p->g->sets = (cset *)malloc(nc * sizeof(cset)); else p->g->sets = (cset *)realloc((char *)p->g->sets, nc * sizeof(cset)); if (p->g->setbits == NULL) p->g->setbits = (uch *)malloc(nbytes); else { p->g->setbits = (uch *)realloc((char *)p->g->setbits, nbytes); /* xxx this isn't right if setbits is now NULL */ for (i = 0; i < no; i++) p->g->sets[i].ptr = p->g->setbits + css*(i/CHAR_BIT); } if (p->g->sets != NULL && p->g->setbits != NULL) (void) memset((char *)p->g->setbits + (nbytes - css), 0, css); else { no = 0; SETERROR(REG_ESPACE); /* caller's responsibility not to do set ops */ } } assert(p->g->sets != NULL); /* xxx */ cs = &p->g->sets[no]; cs->ptr = p->g->setbits + css*((no)/CHAR_BIT); cs->mask = 1 << ((no) % CHAR_BIT); cs->hash = 0; cs->smultis = 0; cs->multis = NULL; return(cs); } /* - freeset - free a now-unused set == static void freeset(register struct parse *p, register cset *cs); */ static void freeset(p, cs) register struct parse *p; register cset *cs; { register int i; register cset *top = &p->g->sets[p->g->ncsets]; register size_t css = (size_t)p->g->csetsize; for (i = 0; i < css; i++) CHsub(cs, i); if (cs == top-1) /* recover only the easy case */ p->g->ncsets--; } /* - freezeset - final processing on a set of characters == static int freezeset(register struct parse *p, register cset *cs); * * The main task here is merging identical sets. This is usually a waste * of time (although the hash code minimizes the overhead), but can win * big if REG_ICASE is being used. REG_ICASE, by the way, is why the hash * is done using addition rather than xor -- all ASCII [aA] sets xor to * the same value! */ static int /* set number */ freezeset(p, cs) register struct parse *p; register cset *cs; { register uch h = cs->hash; register int i; register cset *top = &p->g->sets[p->g->ncsets]; register cset *cs2; register size_t css = (size_t)p->g->csetsize; /* look for an earlier one which is the same */ for (cs2 = &p->g->sets[0]; cs2 < top; cs2++) if (cs2->hash == h && cs2 != cs) { /* maybe */ for (i = 0; i < css; i++) if (!!CHIN(cs2, i) != !!CHIN(cs, i)) break; /* no */ if (i == css) break; /* yes */ } if (cs2 < top) { /* found one */ freeset(p, cs); cs = cs2; } return((int)(cs - p->g->sets)); } /* - firstch - return first character in a set (which must have at least one) == static int firstch(register struct parse *p, register cset *cs); */ static int /* character; there is no "none" value */ firstch(p, cs) register struct parse *p; register cset *cs; { register int i; register size_t css = (size_t)p->g->csetsize; for (i = 0; i < css; i++) if (CHIN(cs, i)) return((char)i); assert(never); return(0); /* arbitrary */ } /* - nch - number of characters in a set == static int nch(register struct parse *p, register cset *cs); */ static int nch(p, cs) register struct parse *p; register cset *cs; { register int i; register size_t css = (size_t)p->g->csetsize; register int n = 0; for (i = 0; i < css; i++) if (CHIN(cs, i)) n++; return(n); } /* - mcadd - add a collating element to a cset == static void mcadd(register struct parse *p, register cset *cs, \ == register char *cp); */ static void mcadd(p, cs, cp) register struct parse *p; register cset *cs; register char *cp; { register size_t oldend = cs->smultis; void *np; cs->smultis += strlen(cp) + 1; if (cs->multis == NULL) np = malloc(cs->smultis); else np = realloc(cs->multis, cs->smultis); if (np == NULL) { if (cs->multis) free(cs->multis); cs->multis = NULL; SETERROR(REG_ESPACE); return; } cs->multis = np; (void) strcpy(cs->multis + oldend - 1, cp); cs->multis[cs->smultis - 1] = '\0'; } /* - mcinvert - invert the list of collating elements in a cset == static void mcinvert(register struct parse *p, register cset *cs); * * This would have to know the set of possibilities. Implementation * is deferred. */ /* ARGSUSED */ static void mcinvert(p, cs) register struct parse *p; register cset *cs; { assert(cs->multis == NULL); /* xxx */ } /* - mccase - add case counterparts of the list of collating elements in a cset == static void mccase(register struct parse *p, register cset *cs); * * This would have to know the set of possibilities. Implementation * is deferred. */ /* ARGSUSED */ static void mccase(p, cs) register struct parse *p; register cset *cs; { assert(cs->multis == NULL); /* xxx */ } /* - isinsets - is this character in any sets? == static int isinsets(register struct re_guts *g, int c); */ static int /* predicate */ isinsets(g, c) register struct re_guts *g; int c; { register uch *col; register int i; register int ncols = (g->ncsets+(CHAR_BIT-1)) / CHAR_BIT; register unsigned uc = (unsigned char)c; for (i = 0, col = g->setbits; i < ncols; i++, col += g->csetsize) if (col[uc] != 0) return(1); return(0); } /* - samesets - are these two characters in exactly the same sets? == static int samesets(register struct re_guts *g, int c1, int c2); */ static int /* predicate */ samesets(g, c1, c2) register struct re_guts *g; int c1; int c2; { register uch *col; register int i; register int ncols = (g->ncsets+(CHAR_BIT-1)) / CHAR_BIT; register unsigned uc1 = (unsigned char)c1; register unsigned uc2 = (unsigned char)c2; for (i = 0, col = g->setbits; i < ncols; i++, col += g->csetsize) if (col[uc1] != col[uc2]) return(0); return(1); } /* - categorize - sort out character categories == static void categorize(struct parse *p, register struct re_guts *g); */ static void categorize(p, g) struct parse *p; register struct re_guts *g; { register cat_t *cats = g->categories; register int c; register int c2; register cat_t cat; /* avoid making error situations worse */ if (p->error != 0) return; for (c = CHAR_MIN; c <= CHAR_MAX; c++) if (cats[c] == 0 && isinsets(g, c)) { cat = g->ncategories++; cats[c] = cat; for (c2 = c+1; c2 <= CHAR_MAX; c2++) if (cats[c2] == 0 && samesets(g, c, c2)) cats[c2] = cat; } } /* - dupl - emit a duplicate of a bunch of sops == static sopno dupl(register struct parse *p, sopno start, sopno finish); */ static sopno /* start of duplicate */ dupl(p, start, finish) register struct parse *p; sopno start; /* from here */ sopno finish; /* to this less one */ { register sopno ret = HERE(); register sopno len = finish - start; assert(finish >= start); if (len == 0) return(ret); enlarge(p, p->ssize + len); /* this many unexpected additions */ assert(p->ssize >= p->slen + len); (void) memcpy((char *)(p->strip + p->slen), (char *)(p->strip + start), (size_t)len*sizeof(sop)); p->slen += len; return(ret); } /* - doemit - emit a strip operator == static void doemit(register struct parse *p, sop op, size_t opnd); * * It might seem better to implement this as a macro with a function as * hard-case backup, but it's just too big and messy unless there are * some changes to the data structures. Maybe later. */ static void doemit(p, op, opnd) register struct parse *p; sop op; size_t opnd; { /* avoid making error situations worse */ if (p->error != 0) return; /* deal with oversize operands ("can't happen", more or less) */ assert(opnd < 1<slen >= p->ssize) enlarge(p, (p->ssize+1) / 2 * 3); /* +50% */ assert(p->slen < p->ssize); /* finally, it's all reduced to the easy case */ p->strip[p->slen++] = SOP(op, opnd); } /* - doinsert - insert a sop into the strip == static void doinsert(register struct parse *p, sop op, size_t opnd, sopno pos); */ static void doinsert(p, op, opnd, pos) register struct parse *p; sop op; size_t opnd; sopno pos; { register sopno sn; register sop s; register int i; /* avoid making error situations worse */ if (p->error != 0) return; sn = HERE(); EMIT(op, opnd); /* do checks, ensure space */ assert(HERE() == sn+1); s = p->strip[sn]; /* adjust paren pointers */ assert(pos > 0); for (i = 1; i < NPAREN; i++) { if (p->pbegin[i] >= pos) { p->pbegin[i]++; } if (p->pend[i] >= pos) { p->pend[i]++; } } memmove((char *)&p->strip[pos+1], (char *)&p->strip[pos], (HERE()-pos-1)*sizeof(sop)); p->strip[pos] = s; } /* - dofwd - complete a forward reference == static void dofwd(register struct parse *p, sopno pos, sop value); */ static void dofwd(p, pos, value) register struct parse *p; register sopno pos; sop value; { /* avoid making error situations worse */ if (p->error != 0) return; assert(value < 1<strip[pos] = OP(p->strip[pos]) | value; } /* - enlarge - enlarge the strip == static void enlarge(register struct parse *p, sopno size); */ static void enlarge(p, size) register struct parse *p; register sopno size; { register sop *sp; if (p->ssize >= size) return; sp = (sop *)realloc(p->strip, size*sizeof(sop)); if (sp == NULL) { SETERROR(REG_ESPACE); return; } p->strip = sp; p->ssize = size; } /* - stripsnug - compact the strip == static void stripsnug(register struct parse *p, register struct re_guts *g); */ static void stripsnug(p, g) register struct parse *p; register struct re_guts *g; { g->nstates = p->slen; g->strip = (sop *)realloc((char *)p->strip, p->slen * sizeof(sop)); if (g->strip == NULL) { SETERROR(REG_ESPACE); g->strip = p->strip; } } /* - findmust - fill in must and mlen with longest mandatory literal string == static void findmust(register struct parse *p, register struct re_guts *g); * * This algorithm could do fancy things like analyzing the operands of | * for common subsequences. Someday. This code is simple and finds most * of the interesting cases. * * Note that must and mlen got initialized during setup. */ static void findmust(p, g) struct parse *p; register struct re_guts *g; { register sop *scan; sop *start; register sop *newstart; register sopno newlen; register sop s; register char *cp; register sopno i; /* avoid making error situations worse */ if (p->error != 0) return; /* find the longest OCHAR sequence in strip */ newlen = 0; scan = g->strip + 1; do { s = *scan++; switch (OP(s)) { case OCHAR: /* sequence member */ if (newlen == 0) /* new sequence */ newstart = scan - 1; newlen++; break; case OPLUS_: /* things that don't break one */ case OLPAREN: case ORPAREN: break; case OQUEST_: /* things that must be skipped */ case OCH_: scan--; do { scan += OPND(s); s = *scan; /* assert() interferes w debug printouts */ if (OP(s) != O_QUEST && OP(s) != O_CH && OP(s) != OOR2) { g->iflags |= BAD; return; } } while (OP(s) != O_QUEST && OP(s) != O_CH); /* fallthrough */ default: /* things that break a sequence */ if (newlen > g->mlen) { /* ends one */ start = newstart; g->mlen = newlen; } newlen = 0; break; } } while (OP(s) != OEND); if (g->mlen == 0) /* there isn't one */ return; /* turn it into a character string */ g->must = malloc((size_t)g->mlen + 1); if (g->must == NULL) { /* argh; just forget it */ g->mlen = 0; return; } cp = g->must; scan = start; for (i = g->mlen; i > 0; i--) { while (OP(s = *scan++) != OCHAR) continue; assert(cp < g->must + g->mlen); *cp++ = (char)OPND(s); } assert(cp == g->must + g->mlen); *cp++ = '\0'; /* just on general principles */ } /* - pluscount - count + nesting == static sopno pluscount(register struct parse *p, register struct re_guts *g); */ static sopno /* nesting depth */ pluscount(p, g) struct parse *p; register struct re_guts *g; { register sop *scan; register sop s; register sopno plusnest = 0; register sopno maxnest = 0; if (p->error != 0) return(0); /* there may not be an OEND */ scan = g->strip + 1; do { s = *scan++; switch (OP(s)) { case OPLUS_: plusnest++; break; case O_PLUS: if (plusnest > maxnest) maxnest = plusnest; plusnest--; break; } } while (OP(s) != OEND); if (plusnest != 0) g->iflags |= BAD; return(maxnest); } sma-1.4.orig/regex/regerror.c0000644000175000017500000001242007603333515016400 0ustar apollockapollock/*- * Copyright (c) 1992, 1993, 1994 Henry Spencer. * Copyright (c) 1992, 1993, 1994 * The Regents of the University of California. All rights reserved. * * This code is derived from software contributed to Berkeley by * Henry Spencer. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * @(#)regerror.c 8.4 (Berkeley) 3/20/94 */ #include #include #include #include #include #include #include #include "utils.h" /* ========= begin header generated by ./mkh ========= */ #ifdef __cplusplus extern "C" { #endif /* === regerror.c === */ static char *regatoi __P((const regex_t *preg, char *localbuf)); #ifdef __cplusplus } #endif /* ========= end header generated by ./mkh ========= */ /* = #define REG_NOMATCH 1 = #define REG_BADPAT 2 = #define REG_ECOLLATE 3 = #define REG_ECTYPE 4 = #define REG_EESCAPE 5 = #define REG_ESUBREG 6 = #define REG_EBRACK 7 = #define REG_EPAREN 8 = #define REG_EBRACE 9 = #define REG_BADBR 10 = #define REG_ERANGE 11 = #define REG_ESPACE 12 = #define REG_BADRPT 13 = #define REG_EMPTY 14 = #define REG_ASSERT 15 = #define REG_INVARG 16 = #define REG_ATOI 255 // convert name to number (!) = #define REG_ITOA 0400 // convert number to name (!) */ static struct rerr { int code; char *name; char *explain; } rerrs[] = { { REG_NOMATCH, "REG_NOMATCH", "regexec() failed to match" }, { REG_BADPAT, "REG_BADPAT", "invalid regular expression" }, { REG_ECOLLATE, "REG_ECOLLATE", "invalid collating element" }, { REG_ECTYPE, "REG_ECTYPE", "invalid character class" }, { REG_EESCAPE, "REG_EESCAPE", "trailing backslash (\\)" }, { REG_ESUBREG, "REG_ESUBREG", "invalid backreference number" }, { REG_EBRACK, "REG_EBRACK", "brackets ([ ]) not balanced" }, { REG_EPAREN, "REG_EPAREN", "parentheses not balanced" }, { REG_EBRACE, "REG_EBRACE", "braces not balanced" }, { REG_BADBR, "REG_BADBR", "invalid repetition count(s)" }, { REG_ERANGE, "REG_ERANGE", "invalid character range" }, { REG_ESPACE, "REG_ESPACE", "out of memory" }, { REG_BADRPT, "REG_BADRPT", "repetition-operator operand invalid" }, { REG_EMPTY, "REG_EMPTY", "empty (sub)expression" }, { REG_ASSERT, "REG_ASSERT", "\"can't happen\" -- you found a bug" }, { REG_INVARG, "REG_INVARG", "invalid argument to regex routine" }, { 0, "", "*** unknown regexp error code ***" } }; /* - regerror - the interface to error numbers = extern size_t regerror(int, const regex_t *, char *, size_t); */ /* ARGSUSED */ size_t regerror(errcode, preg, errbuf, errbuf_size) int errcode; const regex_t *preg; char *errbuf; size_t errbuf_size; { register struct rerr *r; register size_t len; register int target = errcode &~ REG_ITOA; register char *s; char convbuf[50]; if (errcode == REG_ATOI) s = regatoi(preg, convbuf); else { for (r = rerrs; r->code != 0; r++) if (r->code == target) break; if (errcode®_ITOA) { if (r->code != 0) { assert(strlen(r->name) < sizeof(convbuf)); (void) strcpy(convbuf, r->name); } else (void)sprintf(convbuf, "REG_0x%x", target); s = convbuf; } else s = r->explain; } len = strlen(s) + 1; if (errbuf_size > 0) { (void) strncpy(errbuf, s, errbuf_size-1); errbuf[errbuf_size-1] = '\0'; } return(len); } /* - regatoi - internal routine to implement REG_ATOI == static char *regatoi(const regex_t *preg, char *localbuf); */ static char * regatoi(preg, localbuf) const regex_t *preg; char *localbuf; { register struct rerr *r; for (r = rerrs; r->code != 0; r++) if (strcmp(r->name, preg->re_endp) == 0) break; if (r->code == 0) return("0"); (void)sprintf(localbuf, "%d", r->code); return(localbuf); } sma-1.4.orig/regex/regex.h0000444000175000017500000000734307603333515015676 0ustar apollockapollock/*- * Copyright (c) 1992 Henry Spencer. * Copyright (c) 1992, 1993 * The Regents of the University of California. All rights reserved. * * This code is derived from software contributed to Berkeley by * Henry Spencer of the University of Toronto. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * @(#)regex.h 8.1 (Berkeley) 6/2/93 */ #ifndef _REGEX_H_ #define _REGEX_H_ #ifdef _WIN32 #include #define __const #define __BEGIN_DECLS #define __END_DECLS #define __P(_X) _X #else #include #endif /* types */ typedef off_t regoff_t; typedef struct { int re_magic; size_t re_nsub; /* number of parenthesized subexpressions */ const char *re_endp; /* end pointer for REG_PEND */ struct re_guts *re_g; /* none of your business :-) */ } regex_t; typedef struct { regoff_t rm_so; /* start of match */ regoff_t rm_eo; /* end of match */ } regmatch_t; /* regcomp() flags */ #define REG_BASIC 0000 #define REG_EXTENDED 0001 #define REG_ICASE 0002 #define REG_NOSUB 0004 #define REG_NEWLINE 0010 #define REG_NOSPEC 0020 #define REG_PEND 0040 #define REG_DUMP 0200 /* regerror() flags */ #define REG_NOMATCH 1 #define REG_BADPAT 2 #define REG_ECOLLATE 3 #define REG_ECTYPE 4 #define REG_EESCAPE 5 #define REG_ESUBREG 6 #define REG_EBRACK 7 #define REG_EPAREN 8 #define REG_EBRACE 9 #define REG_BADBR 10 #define REG_ERANGE 11 #define REG_ESPACE 12 #define REG_BADRPT 13 #define REG_EMPTY 14 #define REG_ASSERT 15 #define REG_INVARG 16 #define REG_ATOI 255 /* convert name to number (!) */ #define REG_ITOA 0400 /* convert number to name (!) */ /* regexec() flags */ #define REG_NOTBOL 00001 #define REG_NOTEOL 00002 #define REG_STARTEND 00004 #define REG_TRACE 00400 /* tracing of execution */ #define REG_LARGE 01000 /* force large representation */ #define REG_BACKR 02000 /* force use of backref code */ __BEGIN_DECLS int regcomp __P((regex_t *, const char *, int)); size_t regerror __P((int, const regex_t *, char *, size_t)); int regexec __P((const regex_t *, const char *, size_t, regmatch_t [], int)); void regfree __P((regex_t *)); __END_DECLS #endif /* !_REGEX_H_ */ sma-1.4.orig/regex/regex2.h0000644000175000017500000001642307603333515015761 0ustar apollockapollock/*- * Copyright (c) 1992, 1993, 1994 Henry Spencer. * Copyright (c) 1992, 1993, 1994 * The Regents of the University of California. All rights reserved. * * This code is derived from software contributed to Berkeley by * Henry Spencer. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * @(#)regex2.h 8.4 (Berkeley) 3/20/94 */ /* * First, the stuff that ends up in the outside-world include file = typedef off_t regoff_t; = typedef struct { = int re_magic; = size_t re_nsub; // number of parenthesized subexpressions = const char *re_endp; // end pointer for REG_PEND = struct re_guts *re_g; // none of your business :-) = } regex_t; = typedef struct { = regoff_t rm_so; // start of match = regoff_t rm_eo; // end of match = } regmatch_t; */ /* * internals of regex_t */ #define MAGIC1 ((('r'^0200)<<8) | 'e') /* * The internal representation is a *strip*, a sequence of * operators ending with an endmarker. (Some terminology etc. is a * historical relic of earlier versions which used multiple strips.) * Certain oddities in the representation are there to permit running * the machinery backwards; in particular, any deviation from sequential * flow must be marked at both its source and its destination. Some * fine points: * * - OPLUS_ and O_PLUS are *inside* the loop they create. * - OQUEST_ and O_QUEST are *outside* the bypass they create. * - OCH_ and O_CH are *outside* the multi-way branch they create, while * OOR1 and OOR2 are respectively the end and the beginning of one of * the branches. Note that there is an implicit OOR2 following OCH_ * and an implicit OOR1 preceding O_CH. * * In state representations, an operator's bit is on to signify a state * immediately *preceding* "execution" of that operator. */ typedef unsigned long sop; /* strip operator */ typedef long sopno; #define OPRMASK 0xf8000000LU #define OPDMASK 0x07ffffffLU #define OPSHIFT ((unsigned)27) #define OP(n) ((n)&OPRMASK) #define OPND(n) ((n)&OPDMASK) #define SOP(op, opnd) ((op)|(opnd)) /* operators meaning operand */ /* (back, fwd are offsets) */ #define OEND (1LU< uch [csetsize] */ uch mask; /* bit within array */ uch hash; /* hash code */ size_t smultis; char *multis; /* -> char[smulti] ab\0cd\0ef\0\0 */ } cset; /* note that CHadd and CHsub are unsafe, and CHIN doesn't yield 0/1 */ #define CHadd(cs, c) ((cs)->ptr[(uch)(c)] |= (cs)->mask, (cs)->hash += (c)) #define CHsub(cs, c) ((cs)->ptr[(uch)(c)] &= ~(cs)->mask, (cs)->hash -= (c)) #define CHIN(cs, c) ((cs)->ptr[(uch)(c)] & (cs)->mask) #define MCadd(p, cs, cp) mcadd(p, cs, cp) /* regcomp() internal fns */ #define MCsub(p, cs, cp) mcsub(p, cs, cp) #define MCin(p, cs, cp) mcin(p, cs, cp) /* stuff for character categories */ typedef unsigned char cat_t; /* * main compiled-expression structure */ struct re_guts { int magic; # define MAGIC2 ((('R'^0200)<<8)|'E') sop *strip; /* malloced area for strip */ int csetsize; /* number of bits in a cset vector */ int ncsets; /* number of csets in use */ cset *sets; /* -> cset [ncsets] */ uch *setbits; /* -> uch[csetsize][ncsets/CHAR_BIT] */ int cflags; /* copy of regcomp() cflags argument */ sopno nstates; /* = number of sops */ sopno firststate; /* the initial OEND (normally 0) */ sopno laststate; /* the final OEND */ int iflags; /* internal flags */ # define USEBOL 01 /* used ^ */ # define USEEOL 02 /* used $ */ # define BAD 04 /* something wrong */ int nbol; /* number of ^ used */ int neol; /* number of $ used */ int ncategories; /* how many character categories */ cat_t *categories; /* ->catspace[-CHAR_MIN] */ char *must; /* match must contain this string */ int mlen; /* length of must */ size_t nsub; /* copy of re_nsub */ int backrefs; /* does it use back references? */ sopno nplus; /* how deep does it nest +s? */ /* catspace must be last */ cat_t catspace[1]; /* actually [NC] */ }; /* misc utilities */ #define OUT (CHAR_MAX+1) /* a non-character value */ #define ISWORD(c) (isalnum(c) || (c) == '_') sma-1.4.orig/regex/regexec.c0000644000175000017500000001414407603333515016200 0ustar apollockapollock/*- * Copyright (c) 1992, 1993, 1994 Henry Spencer. * Copyright (c) 1992, 1993, 1994 * The Regents of the University of California. All rights reserved. * * This code is derived from software contributed to Berkeley by * Henry Spencer. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * @(#)regexec.c 8.3 (Berkeley) 3/20/94 */ /* * the outer shell of regexec() * * This file includes engine.c *twice*, after muchos fiddling with the * macros that code uses. This lets the same code operate on two different * representations for state sets. */ #include #include #include #include #include #include #include "regex.h" #include "utils.h" #include "regex2.h" /* macros for manipulating states, small version */ #define states long #define states1 states /* for later use in regexec() decision */ #define CLEAR(v) ((v) = 0) #define SET0(v, n) ((v) &= ~((unsigned long)1 << (n))) #define SET1(v, n) ((v) |= (unsigned long)1 << (n)) #define ISSET(v, n) (((v) & ((unsigned long)1 << (n))) != 0) #define ASSIGN(d, s) ((d) = (s)) #define EQ(a, b) ((a) == (b)) #define STATEVARS long dummy /* dummy version */ #define STATESETUP(m, n) /* nothing */ #define STATETEARDOWN(m) /* nothing */ #define SETUP(v) ((v) = 0) #define onestate long #define INIT(o, n) ((o) = (unsigned long)1 << (n)) #define INC(o) ((o) <<= 1) #define ISSTATEIN(v, o) (((v) & (o)) != 0) /* some abbreviations; note that some of these know variable names! */ /* do "if I'm here, I can also be there" etc without branches */ #define FWD(dst, src, n) ((dst) |= ((unsigned long)(src)&(here)) << (n)) #define BACK(dst, src, n) ((dst) |= ((unsigned long)(src)&(here)) >> (n)) #define ISSETBACK(v, n) (((v) & ((unsigned long)here >> (n))) != 0) /* function names */ #define SNAMES /* engine.c looks after details */ #include "engine.c" /* now undo things */ #undef states #undef CLEAR #undef SET0 #undef SET1 #undef ISSET #undef ASSIGN #undef EQ #undef STATEVARS #undef STATESETUP #undef STATETEARDOWN #undef SETUP #undef onestate #undef INIT #undef INC #undef ISSTATEIN #undef FWD #undef BACK #undef ISSETBACK #undef SNAMES /* macros for manipulating states, large version */ #define states char * #define CLEAR(v) memset(v, 0, m->g->nstates) #define SET0(v, n) ((v)[n] = 0) #define SET1(v, n) ((v)[n] = 1) #define ISSET(v, n) ((v)[n]) #define ASSIGN(d, s) memcpy(d, s, m->g->nstates) #define EQ(a, b) (memcmp(a, b, m->g->nstates) == 0) #define STATEVARS long vn; char *space #define STATESETUP(m, nv) { (m)->space = malloc((nv)*(m)->g->nstates); \ if ((m)->space == NULL) return(REG_ESPACE); \ (m)->vn = 0; } #define STATETEARDOWN(m) { free((m)->space); } #define SETUP(v) ((v) = &m->space[m->vn++ * m->g->nstates]) #define onestate long #define INIT(o, n) ((o) = (n)) #define INC(o) ((o)++) #define ISSTATEIN(v, o) ((v)[o]) /* some abbreviations; note that some of these know variable names! */ /* do "if I'm here, I can also be there" etc without branches */ #define FWD(dst, src, n) ((dst)[here+(n)] |= (src)[here]) #define BACK(dst, src, n) ((dst)[here-(n)] |= (src)[here]) #define ISSETBACK(v, n) ((v)[here - (n)]) /* function names */ #define LNAMES /* flag */ #include "engine.c" /* - regexec - interface for matching = extern int regexec(const regex_t *, const char *, size_t, \ = regmatch_t [], int); = #define REG_NOTBOL 00001 = #define REG_NOTEOL 00002 = #define REG_STARTEND 00004 = #define REG_TRACE 00400 // tracing of execution = #define REG_LARGE 01000 // force large representation = #define REG_BACKR 02000 // force use of backref code * * We put this here so we can exploit knowledge of the state representation * when choosing which matcher to call. Also, by this point the matchers * have been prototyped. */ int /* 0 success, REG_NOMATCH failure */ regexec(preg, string, nmatch, pmatch, eflags) const regex_t *preg; const char *string; size_t nmatch; regmatch_t pmatch[]; int eflags; { register struct re_guts *g = preg->re_g; #ifdef REDEBUG # define GOODFLAGS(f) (f) #else # define GOODFLAGS(f) ((f)&(REG_NOTBOL|REG_NOTEOL|REG_STARTEND)) #endif if (preg->re_magic != MAGIC1 || g->magic != MAGIC2) return(REG_BADPAT); assert(!(g->iflags&BAD)); if (g->iflags&BAD) /* backstop for no-debug case */ return(REG_BADPAT); eflags = GOODFLAGS(eflags); if (g->nstates <= CHAR_BIT*sizeof(states1) && !(eflags®_LARGE)) return(smatcher(g, (char *)string, nmatch, pmatch, eflags)); else return(lmatcher(g, (char *)string, nmatch, pmatch, eflags)); } sma-1.4.orig/regex/regfree.c0000644000175000017500000000526207603333515016176 0ustar apollockapollock/*- * Copyright (c) 1992, 1993, 1994 Henry Spencer. * Copyright (c) 1992, 1993, 1994 * The Regents of the University of California. All rights reserved. * * This code is derived from software contributed to Berkeley by * Henry Spencer. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * @(#)regfree.c 8.3 (Berkeley) 3/20/94 */ #include #include #include #include "regex.h" #include "utils.h" #include "regex2.h" /* - regfree - free everything = extern void regfree(regex_t *); */ void regfree(preg) regex_t *preg; { register struct re_guts *g; if (preg->re_magic != MAGIC1) /* oops */ return; /* nice to complain, but hard */ g = preg->re_g; if (g == NULL || g->magic != MAGIC2) /* oops again */ return; preg->re_magic = 0; /* mark it invalid */ g->magic = 0; /* mark it invalid */ if (g->strip != NULL) free((char *)g->strip); if (g->sets != NULL) free((char *)g->sets); if (g->setbits != NULL) free((char *)g->setbits); if (g->must != NULL) free(g->must); free((char *)g); } sma-1.4.orig/regex/utils.h0000644000175000017500000000476407603333515015732 0ustar apollockapollock/*- * Copyright (c) 1992, 1993, 1994 Henry Spencer. * Copyright (c) 1992, 1993, 1994 * The Regents of the University of California. All rights reserved. * * This code is derived from software contributed to Berkeley by * Henry Spencer. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * @(#)utils.h 8.3 (Berkeley) 3/20/94 */ /* utility definitions */ #ifndef _POSIX2_RE_DUP_MAX #define _POSIX2_RE_DUP_MAX 255 #endif #define DUPMAX _POSIX2_RE_DUP_MAX /* xxx is this right? */ #define INFINITY (DUPMAX + 1) #define NC (CHAR_MAX - CHAR_MIN + 1) typedef unsigned char uch; /* switch off assertions (if not already off) if no REDEBUG */ #ifndef REDEBUG #ifndef NDEBUG #define NDEBUG /* no assertions please */ #endif #endif #include /* for old systems with bcopy() but no memmove() */ #ifdef USEBCOPY #define memmove(d, s, c) bcopy(s, d, c) #endif sma-1.4.orig/sma.c0000644000175000017500000002514007611512042014213 0ustar apollockapollock/* * sma -- Sendmail log analyser * * Copyright (c) 2000 - 2003 Jarkko Turkulainen. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY JARKKO TURKULAINEN ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL JARKKO TURKULAINEN BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $Date: 2002/09/12 10:46:00 $ */ extern const char *sma_optarg; extern int sma_optind; #include "sma.h" int main(int argc, char **argv) { FILE *fp = NULL; struct host *hptr; int c; #ifdef _WIN32 int getopt(int, char **, char *); #endif /* initialize global variables: */ hosts = 0; tval = time((time_t *)NULL); curr = localtime(&tval); first.next = NULL; pname = argv[0]; /* get arguments: */ while ((c = getopt(argc, argv, "C:D:H:L:b:f:l:r:t:o:O:AFacdhinpsqvw")) != -1) switch(c) { case 'A': dcaddrflag = 1; break; case 'D': Dflag = 1; Dchar = sma_optarg; break; case 'C': Cflag = 1; Cchar = sma_optarg; break; case 'F': Fflag = 1; break; case 'H': Hflag = 1; Hchar = sma_optarg; break; case 'a': aflag = 1; break; case 'b': bflag = 1; bchar = sma_optarg; break; case 'c': cflag = 1; break; case 'd': dflag = 1; break; case 'f': fflag = 1; fchar = sma_optarg; break; case 'h': hflag = 1; break; case 'i': iflag = 1; break; case 'l': lflag = 1; lnum = atoi(sma_optarg); break; case 'L': Lflag = 1; Lchar = sma_optarg; break; case 'r': rflag = 1; rnum = atoi(sma_optarg); break; case 'n': nflag = 1; break; case 'o': oflag = 1; ochar = sma_optarg; break; case 'O': Oflag = 1; Ochar = sma_optarg; break; case 'p': pflag = 1; break; case 's': sflag = 1; break; case 't': tflag = 1; tchar = sma_optarg; break; case 'q': qflag = 1; break; case 'v': vflag = 1; break; case 'w': wflag = 1; break; default: usage(); } argc -= sma_optind; argv += sma_optind; /* Debug */ if (vflag) fprintf(stderr, "%s: running in Debug mode\n", pname); /* Check argument logic: */ if (hflag) usage(); if (cflag) copying(); if (!pgflag) pgflag = 1; /* Read in the configuration file: */ if (fchar) { if (!(fp = fopen(fchar, "r"))) fprintf(stderr, "%s: cannot open %s\n", pname, fchar); else { init(fp); (void)fclose(fp); } } else if (!Fflag) { if (!(fp = fopen(DEFAULT_CONF, "r"))) fprintf(stderr, "%s: cannot open %s, using defaults\n", pname, "configuration file"); else { fchar = DEFAULT_CONF; init(fp); (void)fclose(fp); } } /* Hash table size: */ if (!tflag || !strncmp(tchar, "normal", 6)) { asize = ASIZE_NORMAL; rsize = RSIZE_NORMAL; } else if (!strncmp(tchar, "big", 3)) { asize = ASIZE_BIG; rsize = RSIZE_BIG; } else if (!strncmp(tchar, "huge", 4)) { asize = ASIZE_HUGE; rsize = RSIZE_HUGE; } else { if (!(hsstring = strdup(tchar))) error_memory(); hastring = hsstring; if (*hsstring == ',') { hastring = NULL; if (*(hsstring + 1) == '\0') hrstring = NULL; else hrstring = ++hsstring; } while (*hsstring != '\0') { if (*hsstring == ',') { *hsstring = '\0'; if (*(hsstring + 1) == '\0') hrstring = NULL; else hrstring = ++hsstring; break; } hsstring++; } /* Address Hash table: */ if (hastring != NULL) asize = atoi(hastring); else asize = ASIZE_NORMAL; /* Relay Hash table: */ if (hrstring != NULL) rsize = atoi(hrstring); else rsize = RSIZE_NORMAL; } if (asize <= 0 || rsize <= 0) { fprintf(stderr, "%s: Illegal hash table size\n", pname); usage(); } if (!Oflag) Oflag = FORMAT_ASCII; else if (!strncmp(Ochar, "ascii", 5)) Oflag = FORMAT_ASCII; else if (!strncmp(Ochar, "html", 4)) Oflag = FORMAT_HTML; else if (!strncmp(Ochar, "clog", 4)) Oflag = FORMAT_CLOG; else { fprintf(stderr, "%s: illegal output format \"%s\".\n", pname, Ochar); exit (1); } if (aflag) Oflag = FORMAT_ASCII; if (wflag) Oflag = FORMAT_HTML; if (!Cchar) Cchar = COMMENT; if (aflag) wflag = 0; if (!bchar) bchar = BG_COLOR; if (!tbchar) tbchar = TB_COLOR; if (!bechar) bechar = BOUNCE_ADDR; if (lflag) { if (lnum <= 0) lnum = 0; lrnum = lnum; } else if (!lrflag) { lnum = LDEF; if (lnum <= 0) lnum = 0; lrnum = LRDEF; if (lrnum <= 0) lrnum = 0; } if (rflag) { if (rnum <= 0) rnum = 0; rrnum = rnum; } else if (!rrflag) { rnum = RDEF; if (rnum <= 0) rnum = 0; rrnum = RRDEF; if (rrnum <= 0) rrnum = 0; } /* Set output: */ if (ochar) { if (!(ofp = fopen(ochar, "w"))) { fprintf(stderr, "%s: cannot open %s\n", pname, ochar); ofp = stdout; } } else ofp = stdout; /* Check filter logic: */ /* Envelope and relay filters: */ if (sef || srf || ref || rrf) { if (!qflag) fprintf(stderr, "%s: setting filters\n", pname); #ifdef USE_REGEXP if (csflag) csflag = REG_EXTENDED|REG_NOSUB; else csflag = REG_EXTENDED|REG_ICASE|REG_NOSUB; #endif } if (!sef || !strncmp(sef, "*", 1)) { sef = (char *)NULL; } else { #ifdef USE_REGEXP if (*sef == '!') { if (*(sef+1) == '\0') sef = NULL; regcomp(&csef, sef+1, csflag); } else regcomp(&csef, sef, csflag); #else if (*sef == '!' && *(sef+1) == '\0') sef = (char *)NULL; #endif if (!qflag) fprintf(stderr, " envelope sender filter: %s\n", sef); } if (!srf || !strncmp(srf, "*", 1)) srf = (char *)NULL; else { #ifdef USE_REGEXP if (*srf == '!') { if (*(srf+1) == '\0') srf = NULL; regcomp(&csrf, srf+1, csflag); } else regcomp(&csrf, srf, csflag); #else if (*srf == '!' && *(srf+1) == '\0') srf = (char *)NULL; #endif if (!qflag) fprintf(stderr, " relay sender filter: %s\n", srf); } if (!ref || !strncmp(ref, "*", 1)) ref = (char *)NULL; else { #ifdef USE_REGEXP if (*ref == '!') regcomp(&cref, ref+1, csflag); else regcomp(&cref, ref, csflag); #else if (*ref == '!' && *(ref+1) == '\0') ref = (char *)NULL; #endif if (!qflag) fprintf(stderr, " envelope recipient filter: %s\n", ref); } if (!rrf || !strncmp(rrf, "*", 1)) rrf = (char *)NULL; else { #ifdef USE_REGEXP if (*rrf == '!') regcomp(&crrf, rrf+1, csflag); else regcomp(&crrf, rrf, csflag); #else if (*rrf == '!' && *(rrf+1) == '\0') rrf = (char *)NULL; #endif if (!qflag) fprintf(stderr, " relay recipient filter: %s\n", rrf); } /* Start -and end times: */ if (Dflag) { /* Read from command line.. */ if (!(sstring = strdup(Dchar))) error_memory(); tstring = sstring; if (*sstring == ',') { tstring = NULL; if (*(sstring + 1) == '\0') estring = NULL; else estring = ++sstring; } while (*sstring != '\0') { if (*sstring == ',') { *sstring = '\0'; if (*(sstring + 1) == '\0') estring = NULL; else estring = ++sstring; break; } sstring++; } /* StartTime: */ if (tstring != NULL) scan_time(&sstime, tstring); /* EndTime: */ if (estring != NULL) scan_time(&eetime, estring); } else { if (!sstring || !(strncmp(sstring, "*", 1))) sstring = NULL; else if (sscanf(sstring, "%d/%d/%d-%d:%d:%d", &syear, &smonth, &sday, &shour, &sminute, &ssecond) != 6) { sstring = NULL; if (!qflag) { fprintf(stderr, "%s: illegal StartTime, " "using (*)\n", pname); } } else { sstime = (time_t)conv_time(smonth-1, sday, shour, sminute, ssecond); if (!sstime && !qflag) fprintf(stderr, "%s: illegal StartTime, " "using (*)\n", pname); } if (!estring || !(strncmp(estring, "*", 1))) estring = NULL; else if (sscanf(estring, "%d/%d/%d-%d:%d:%d", &eyear, &emonth, &eday, &ehour, &eminute, &esecond) != 6) { if (!qflag) { fprintf(stderr, "%s: illegal EndTime, " "using (*)\n", pname); } } else { eetime = (time_t)conv_time(emonth-1, eday, ehour, eminute, esecond); if (!eetime && !qflag) fprintf(stderr, "%s: illegal EndTime, " "using (*)\n", pname); } } /* Print out configuration to stdout: */ if (pflag) { fprintf(stderr, "%s: configuration:\n", pname); dump_config(stdout); exit (0); } /* Print configuration in debug mode: */ if (vflag) { fprintf(stderr, "%s: configuration:\n", pname); dump_config(stderr); } /* loop through remaining arguments (if any) and do parsing: */ if (*argv) for (; *argv; ++argv) { if (!qflag) fprintf(stderr, "%s: opening file %s\n", pname, *argv); if (!(fp = fopen(*argv, "r"))) fprintf(stderr, "%s: cannot open %s\n", pname, *argv); else { parse(fp, *argv); (void)fclose(fp); } } else { if (!qflag) fprintf(stderr, "%s: reading from stdin\n", pname); parse(stdin, "stdin"); } /* If output format is clog, nothing to do here: */ if (Oflag == FORMAT_CLOG) exit (0); /* check host structure: */ hptr = first.next; if (!hptr || !(hptr->inum) || !(hptr->onum)) { if (!qflag) fprintf(stderr, "%s: nothing to report\n", pname); exit(1); } for (hptr = first.next; hptr; hptr = hptr->next) { /* rearrange and sort: */ sort(hptr); /* seconds between first and last log entry: */ hptr->dtime = difftime(hptr->ltime, hptr->ftime); /* first hour and day: */ hptr->fday = (localtime(&hptr->ftime))->tm_wday; hptr->fhour = (localtime(&hptr->ftime))->tm_hour; /* time distributions: */ average(hptr, hptr->idd, hptr->fidd, hptr->ihh, hptr->fihh); average(hptr, hptr->odd, hptr->fodd, hptr->ohh, hptr->fohh); } /* print: */ if (Oflag == FORMAT_HTML) html(ofp); else if (Oflag == FORMAT_ASCII) ascii(ofp); (void)fclose(ofp); /* OK: */ exit(0); } sma-1.4.orig/sma.conf0000644000175000017500000001100607642602507014724 0ustar apollockapollock# # sma.conf -- configuration file for SMA # # All configuration options are key-value pairs separated with one # or more space characters: # # "Key" [spaces] "Value" # # Quotation marks are optional - they are needed only if the value contains # space characters (space or tab). Quotation marks inside the value string # must be escaped using a backslash: # # "Key" [spaces] "Value \"containing quotation marks\"" # # Comment lines (lines starting with '#') and empty lines are discarded. # # This always is printed at the top of the report. Comment "Sendmail Log Analysis Report" # You need this if SMA cannot find your hostname from the log files # (Sendmail for NT) or if you want to override it. #HostName myhost.com # Print output as file (same as command line option -o) # If not given, write to stdout #OutFile /home/jt/report.html # # Filtering # # Simple substring filters for envelopes and relays. All filters are ANDed. # If compiled with USE_REGEXP, full suite of extended regexp may be used. # If you set "ShowUsers" as "no", be sure that your filters are applied # against only the domain portion of addresses. # EnvelopeSenderFilter * EnvelopeRecipientFilter * RelaySenderFilter * RelayRecipientFilter * # If compiled with USE_REGEXP, set case sensitivity CaseSensitive no # Start and end times - process log entry only if the time is between # these two. Format: YYYY/MM/DD-HH:MM:SS (example: 2002/06/30-16:25:00 # means Jun 30 16:25:00 2002) #StartTime YYYY/MM/DD-HH:MM:SS #EndTime YYYY/MM/DD-HH:MM:SS # # Output format (html/ascii/clog) # # html - HTML report # ascii - ASCII report # clog - Custom Log format Format html # # HTML Formatting # # Include ASCII report as HTML comment? # Great for easy reading of html docs or mailing the report off to admin. IncludeAscii no # Background colors for HTML BgColor E9E5DF TbColor CCCCCC # Picture for HTML appears in the upper left corner # If you include this, make sure that your web browser finds it!! #PictureURL "logo.jpg" #PictureALT "Logo" # Normal HTML parameters for Picture IMG Tag (for scaling etc..) #PictureParameters "BORDER=0" # Set this if you want your picture to point somewhere #PictureLink "http://www.company.com" # Header -and footer texts # These are those funky "Generated by..." and "Copyright..." notices. #HeaderText "This is header" #FooterText "This is footer" # # Flags for Custom Log (clog) Formatting # Available formatting flags are: # # %U time in UNIX time format # %D time in form "Wed Jun 30 21:49:08 1993" # %y year, four digits # %m month, in digits # %M month, three letter English # %n minute # %s second # %d day # %h hour # %H hostname # %z size in bytes # %f envelope sender # %t envelope recipient # %F relay sender # %T relay recipient # %S status (1 = sent, 0 = error) # %i message id # %% %-character # \n newline # \t tab stop # \\ single backslash # ClogFormat "%D: %i from=%f, to=%t, size=%z" # Print only sent messages (status = 1) (yes/no) ClogSentOnly yes # Syslog Tag, typically sendmail # If set, process only lines with a specified tag. #SyslogTag sendmail # Bounce address, typically MAILER-DAEMON # This is used when DSN messages are checked against filters BounceAddress MAILER-DAEMON # # The number of envelope addresses and relays # Individual sections can be disabled by defining "0" as the value. # It might be a good idea to disable all the sections you don't # need, it improves the performance notably. # EnvelopePairs 10 EnvelopeSenders 10 EnvelopeRecipients 10 RelayPairs 5 RelaySenders 5 RelayRecipients 5 # The number of top status messages and ruleset rejections # If set as "0", do not print the section. # Note that Status messages are affected by filters! PrintStatus 10 PrintRuleset 10 RulesetRelays 10 # Print time distribution (yes/no)? PrintTime yes # Print general information (yes/no)? PrintGeneralInfo yes # Show full addresses (yes/no)? # If "no", only the domain portion of addresses are printed (i.e. the # right side of the '@'). If you are filtering, be careful. ShowUsers no # Sort order (number/transfer) Sorting number # Normal log files contain a lot of useless information. With this switch, # you can keep SMA quiet Silent yes # Print debug information (yes/no)? Debug no # Internal hash table size - possible values are: # "normal", "big", "huge" or custom, comma separated values HashTables normal #HashTables big #HashTables huge # Custom values: address and relay hash table sizes, separated with comma ',' #HashTables 1699,101 sma-1.4.orig/sma.h0000644000175000017500000002345707643001131014226 0ustar apollockapollock/* * sma -- Sendmail log analyser * * Copyright (c) 2000, 2001, 2002 Jarkko Turkulainen. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY JARKKO TURKULAINEN ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL JARKKO TURKULAINEN BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $Date: 2003/04/03 12:43:33 $ */ #include "conf.h" #include #include #include #include #include #ifdef USE_REGEXP #include #if defined _WIN32 #include "regex/regex.h" #else /* defined _WIN32 */ #include #endif /* defined _WIN32 */ #endif /* defined USE_REGEXP */ #if !defined _WIN32 #include #endif #define VERSION "1.4" #define FORMAT_ASCII 3 #define FORMAT_HTML 2 #define FORMAT_CLOG 5 /* pointer to program name: */ char *pname; /* current time: */ time_t tval; struct tm *curr; struct tm tp; /* * Command line arguments * xflag sets argument x on/off * xchar is pointer to argument string if x requires an argument */ int aflag; int cflag; int dflag; int hflag; int nflag; int sflag; int qflag; int lflag; int vflag; int wflag; unsigned int lnum; unsigned int lrnum; int rflag; unsigned int rnum; unsigned int rrnum; int bflag; const char *bchar; int fflag; const char *fchar; int oflag; const char *ochar; int Lflag; const char *Lchar; int Oflag; const char *Ochar; int Dflag; const char *Dchar; int pflag; int iflag; int tflag; int dcaddrflag; const char *tchar; /* Configuration file parameters: */ int Hflag; const char *Hchar; int Cflag; const char *Cchar; int Fflag; const char *tbchar; int pgflag; const char *bechar; const char *cfchar; const char *puchar; const char *pachar; const char *plchar; const char *ppchar; const char *htchar; const char *ftchar; int csflag; int lrflag; int rrflag; int clsflag; unsigned int stnum; unsigned int rsnum; unsigned int rsrnum; unsigned int epnum; unsigned int rpnum; /* Start and end times: */ char *sstring; char *estring; char *tstring; time_t sstime; time_t eetime; int syear; int smonth; int sday; int shour; int sminute; int ssecond; int eyear; int emonth; int eday; int ehour; int eminute; int esecond; /* hash table sizes: */ int asize; int rsize; char *hsstring; char *hastring; char *hrstring; /* sender structure: */ struct in { /* next struct: */ struct in *next; /* name of the entry: */ char *name; /* total number of msgs: */ unsigned int num; /* total size: */ long double size; }; /* receiver structure: */ struct out { /* next struct: */ struct out *next; /* name of the entry: */ char *name; /* total number of msgs: */ unsigned int num; /* total size: */ long double size; }; /* input relay struct: */ struct rin { /* next */ struct rin *next; /* name: */ char *name; /* total number: */ unsigned int num; /* total size: */ long double size; }; /* output relay struct: */ struct rout { /* next */ struct rout *next; /* name: */ char *name; /* total number: */ unsigned int num; /* total size: */ long double size; }; /* message id structure: */ struct msgid { /* next */ struct msgid *next; /* message id */ char *id; /* msgid */ char *msgid; /* sender */ char *sender; /* relay */ char *relay; /* hour and day */ int hh; int day; /* size of the msg */ long double size; /* number of msgs */ int num; /* flags */ int flag; }; /* * Structure for out-of-order messages, that is for * messages without "to=" line in log (unknown local user etc.) */ struct omsgid { /* next */ struct omsgid *next; /* message id */ char *id; /* flags */ int flags; }; /* Relay structure for rulesets: */ struct rrelay { /* next */ struct rrelay *next; /* name: */ char *name; /* total number: */ unsigned int num; }; /* Structure for ruleset based rejections */ struct rule { /* next */ struct rule *next; /* Relay structure for rulesets: */ struct rrelay *rrelaytab; struct rrelay **srrelaytab; unsigned int reldif; /* name: */ char *name; /* total number: */ unsigned int num; }; /* Status structure */ struct status { /* next */ struct status *next; /* name: */ char *name; /* total number: */ unsigned int num; }; /* Envelope pair structure */ struct envpair { /* next */ struct envpair *next; /* pairs: */ char *fname; char *tname; /* total number: */ unsigned int num; /* total size: */ long double size; }; /* Relay pair structure */ struct relpair { /* next */ struct relpair *next; /* pairs: */ char *fname; char *tname; /* total number: */ unsigned int num; /* total size: */ long double size; }; /* host structure: */ struct host { /* next struct: */ struct host *next; /* name of the entry: */ char *name; /* envelope pair structures: */ struct envpair **etab; struct envpair **setab; /* pointers to in -and out addresses: */ struct in **itab; struct out **otab; struct in **sitab; struct out **sotab; /* relay pair structures: */ struct relpair **rtab; struct relpair **srtab; /* pointers to in -and out relays: */ struct rin **ritab; struct rout **rotab; struct rin **rsitab; struct rout **rsotab; /* ruleset structures */ struct rule **ruletab; struct rule **sruletab; /* status structures */ struct status **sttab; struct status **ssttab; /* pointer to message id table: */ struct msgid *msgidtab; /* pointer to out-of-order msg ids: */ struct omsgid *omsgidtab; /* start and end times: */ time_t ftime; time_t ltime; time_t cdtime; double dtime; int fday; int lday; int fhour; /* alias table rebuilds: */ int alias; /* SYSERR: */ int hopc; int lcerror; int oserror; /* daemon starts: */ int dstart; /* time tables: */ int ihh[24]; float fihh[24]; int idd[7]; float fidd[7]; int ohh[24]; float fohh[24]; int odd[7]; float fodd[7]; /* total number of msgs: */ unsigned long inum; unsigned long onum; unsigned long rinum; unsigned long ronum; unsigned long gonum; /* stat-fields: Sent, queued, Host unknown, Deferred ...*/ int sent; int queu; int hunk; int uunk; int defe; int rule; int service; int other; /* total size of msgs: */ long double size; long double isize; long double osize; int lsize; int fhost; /* total number of different messages: */ unsigned int edif; /* envelope pairs */ unsigned int rrdif; /* relay pairs */ unsigned int idif; /* input envelope */ unsigned int odif; /* output envelope */ unsigned int ridif; /* input relay */ unsigned int rodif; /* output relay */ unsigned int sdif; /* status messages */ unsigned int rdif; /* rejected messages */ }; /* Filters */ char *sef; char *ref; char *srf; char *rrf; #ifdef USE_REGEXP regex_t csef; regex_t cref; regex_t csrf; regex_t crrf; #endif /* Output file handle: */ FILE *ofp; /* total number of hosts: */ int hosts; /* inital host structure: */ struct host first; /* function definitions: */ void usage(void); void error_memory(void); void parse(FILE *, const char *); time_t conv_time(int, int, int, int, int); int conv_mon(const char *); void copying(void); const char * get_name(char *); const char * get_relay_name(char *); unsigned hash(const char *,int); struct host *init_host(const char *); void update_in(struct host *, const char *, int); void remove_in(struct host *, const char *, int); void update_out(struct host *, const char *, int); void update_rin(struct host *, const char *, int); void remove_rin(struct host *, const char *, int); void update_rout(struct host *, const char *, int); int comp_env(const void *, const void *); int comp_in(const void *, const void *); int comp_out(const void *, const void *); int comp_rel(const void *, const void *); int comp_rin(const void *, const void *); int comp_rout(const void *, const void *); int comp_s(const void *, const void *); int comp_r(const void *, const void *); int comp_rrel(const void *, const void *); void sort(struct host *); void average(struct host *, int *, float *, int *, float *); void html(FILE *); void ascii(FILE *); void init(FILE *); int update_msgid(struct host *, const char *, const char *, const char *, int, int, int, int, const char *); int update_omsgid(struct host *, const char *, int); void check_msgid(struct host *, const char *, int); void remove_msgid(struct host *, const char *); int check_omsgid(struct host *, const char *); struct msgid *get_msgid(struct host *, const char *); char * stripn(char *); char * get_string(char *); void printclog(time_t, const char *, int, const char *, const char *, const char *, const char *, const char *, int); void update_status(struct host *, const char *); void update_ruleset(struct host *, const char *, const char *); void update_envpair(struct host *, const char *, const char *, int); void update_relpair(struct host *, const char *, const char *, int); void scan_time(time_t *, char *); void dump_config(FILE *); /* macros */ #define MIN(a,b) (a > b) ? b : a sma-1.4.orig/utils.c0000644000175000017500000004355007611512042014600 0ustar apollockapollock/* * sma -- Sendmail log analyser * * Copyright (c) 2000 - 2003 Jarkko Turkulainen. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY JARKKO TURKULAINEN ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL JARKKO TURKULAINEN BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $Date: 2002/12/06 12:48:51 $ */ /* Copyright for routines in scan_time() */ /* * Copyright (c) 1985, 1987, 1988, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include "sma.h" int isdigit(int); /* * Take month as an ascii string and return integer */ int conv_mon(const char *mon) { int k; const char *montab[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; for (k = 0; k < 12; k++) { if (!strcmp(mon, montab[k])) break; } return k; } /* * Take month, day, hour, minute and second as integers * and return time_t */ time_t conv_time(int mon, int day, int hh, int min, int sec) { /* * Assume that the year is current year... * This is bug. */ /* sanity check: */ if (mon < 0 || mon >= 12) return (time_t)NULL; /* fill the structure: */ tp.tm_sec=sec; tp.tm_min=min; tp.tm_hour=hh; tp.tm_mday=day; tp.tm_mon=mon; tp.tm_year=curr->tm_year; tp.tm_isdst=-1; return mktime(&tp); } void scan_time(time_t *utime, char *p) { #define ATOI2(ar) ((ar)[0] - '0') * 10 + ((ar)[1] - '0'); (ar) += 2; struct tm *lt; char *t, *dot; int bigyear; int yearset = 0; for (t = p, dot = NULL; *t; ++t) { if (isdigit(*t)) continue; if (*t == '.' && dot == NULL) { dot = t; continue; } usage(); } tval = time((time_t *)NULL); lt = localtime(&tval); lt->tm_isdst = -1; /* correct for DST */ if (dot != NULL) { /* .SS */ *dot++ = '\0'; if (strlen(dot) != 2) usage(); lt->tm_sec = ATOI2(dot); if (lt->tm_sec > 61) usage(); } else lt->tm_sec = 0; switch (strlen(p)) { case 12: /* cc */ bigyear = ATOI2(p); lt->tm_year = bigyear * 100 - 1900; yearset = 1; /* FALLTHROUGH */ case 10: /* yy */ if (yearset) { lt->tm_year += ATOI2(p); } else { lt->tm_year = ATOI2(p); if (lt->tm_year < 69) /* hack for 2000 ;-} */ lt->tm_year += (2000 - 1900); else lt->tm_year += (1900 - 1900); } /* FALLTHROUGH */ case 8: /* mm */ lt->tm_mon = ATOI2(p); if ((lt->tm_mon > 12) || !lt->tm_mon) usage(); --lt->tm_mon; /* time struct is 0 - 11 */ /* FALLTHROUGH */ case 6: /* dd */ lt->tm_mday = ATOI2(p); if ((lt->tm_mday > 31) || !lt->tm_mday) usage(); /* FALLTHROUGH */ case 4: /* HH */ lt->tm_hour = ATOI2(p); if (lt->tm_hour > 23) usage(); /* FALLTHROUGH */ case 2: /* MM */ lt->tm_min = ATOI2(p); if (lt->tm_min > 59) usage(); break; default: usage(); } *utime = mktime(lt); } /* * Prepare a space for sorted address stuctures and do the sorting */ void sort(struct host *hptr) { int i, j, k; struct envpair *eptr; struct in *iptr; struct out *optr; struct relpair *rptr; struct rin *riptr; struct rout *roptr; struct status *statptr; struct rule *ruleptr; struct rrelay *rrptr; /* space for sorted structures: */ if (!(hptr->setab = malloc(hptr->edif * sizeof(struct envpair *)))) error_memory(); if (!(hptr->sitab = malloc(hptr->idif * sizeof(struct sin *)))) error_memory(); if (!(hptr->sotab = malloc(hptr->odif * sizeof(struct sout *)))) error_memory(); if (!(hptr->srtab = malloc(hptr->rrdif * sizeof(struct relpair *)))) error_memory(); if (!(hptr->rsitab = malloc(hptr->ridif * sizeof(struct rin *)))) error_memory(); if (!(hptr->rsotab = malloc(hptr->rodif * sizeof(struct rout *)))) error_memory(); if (!(hptr->ssttab = malloc(hptr->sdif * sizeof(struct status *)))) error_memory(); if (!(hptr->sruletab = malloc(hptr->rdif * sizeof(struct rule *)))) error_memory(); /* envelope pairs: */ for (i = 0, k = 0; k < asize; k++) for (eptr = hptr->etab[k]; eptr; eptr = eptr->next) /* copy pointers: */ hptr->setab[i++] = eptr; /* relay pairs: */ for (i = 0, k = 0; k < rsize; k++) for (rptr = hptr->rtab[k]; rptr; rptr = rptr->next) /* copy pointers: */ hptr->srtab[i++] = rptr; /* input: */ for (i = 0, k = 0; k < asize; k++) for (iptr = hptr->itab[k]; iptr; iptr = iptr->next) /* copy pointers: */ hptr->sitab[i++] = iptr; for (i = 0, k = 0; k < rsize; k++) for (riptr = hptr->ritab[k]; riptr; riptr = riptr->next) /* copy pointers: */ hptr->rsitab[i++] = riptr; /* output: */ for (i = 0, k = 0; k < asize; k++) for (optr = hptr->otab[k]; optr; optr = optr->next) /* copy pointers: */ hptr->sotab[i++] = optr; for (i = 0, k = 0; k < rsize; k++) for (roptr = hptr->rotab[k];roptr; roptr = roptr->next) /* copy pointers: */ hptr->rsotab[i++] = roptr; /* status and ruleset: */ for (i = 0, k = 0; k < rsize; k++) for (statptr = hptr->sttab[k]; statptr; statptr = statptr->next) /* copy pointers: */ hptr->ssttab[i++] = statptr; for (i = 0, k = 0; k < rsize; k++) for (ruleptr = hptr->ruletab[k]; ruleptr; ruleptr = ruleptr->next) { /* copy pointers: */ hptr->sruletab[i++] = ruleptr; /* alloc space for sorted relays: */ if (!(ruleptr->srrelaytab = malloc(ruleptr->reldif * sizeof(struct rrelay *)))) error_memory(); for (j = 0, rrptr = ruleptr->rrelaytab; rrptr; rrptr = rrptr->next) ruleptr->srrelaytab[j++] = rrptr; /* sort */ qsort(ruleptr->srrelaytab, ruleptr->reldif, sizeof(struct rrelay *), comp_rrel); } /* sort */ qsort(hptr->setab, hptr->edif, sizeof(struct envpair *), comp_env); qsort(hptr->sitab, hptr->idif, sizeof(struct in *), comp_in); qsort(hptr->sotab, hptr->odif, sizeof(struct out *), comp_out); qsort(hptr->srtab, hptr->rrdif, sizeof(struct relpair *), comp_rel); qsort(hptr->rsitab, hptr->ridif, sizeof(struct rin *), comp_rin); qsort(hptr->rsotab, hptr->rodif, sizeof(struct rout *), comp_rout); qsort(hptr->ssttab, hptr->sdif, sizeof(struct status *), comp_s); qsort(hptr->sruletab, hptr->rdif, sizeof(struct rule *), comp_r); } /* * Comparing functions, called from sort() */ int comp_env(const void *p1, const void *p2) { const struct envpair * sp1 = *(const struct envpair * const *)p1; const struct envpair * sp2 = *(const struct envpair * const *)p2; if (sflag) { if (sp1->size < sp2->size) return (1); if (sp1->size > sp2->size) return (-1); } else { if (sp1->num < sp2->num) return (1); if (sp1->num > sp2->num) return (-1); } return (0); } int comp_rel(const void *p1, const void *p2) { const struct relpair * sp1 = *(const struct relpair * const *)p1; const struct relpair * sp2 = *(const struct relpair * const *)p2; if (sflag) { if (sp1->size < sp2->size) return (1); if (sp1->size > sp2->size) return (-1); } else { if (sp1->num < sp2->num) return (1); if (sp1->num > sp2->num) return (-1); } return (0); } int comp_in(const void *p1, const void *p2) { const struct in * sp1 = *(const struct in * const *)p1; const struct in * sp2 = *(const struct in * const *)p2; if (sflag) { if (sp1->size < sp2->size) return (1); if (sp1->size > sp2->size) return (-1); } else { if (sp1->num < sp2->num) return (1); if (sp1->num > sp2->num) return (-1); } return (0); } int comp_rin(const void *p1, const void *p2) { const struct rin * sp1 = *(const struct rin * const *)p1; const struct rin * sp2 = *(const struct rin * const *)p2; if (sflag) { if (sp1->size < sp2->size) return (1); if (sp1->size > sp2->size) return (-1); } else { if (sp1->num < sp2->num) return (1); if (sp1->num > sp2->num) return (-1); } return (0); } int comp_out(const void *p1, const void *p2) { const struct out * sp1 = *(const struct out * const *)p1; const struct out * sp2 = *(const struct out * const *)p2; if (sflag) { if (sp1->size < sp2->size) return (1); if (sp1->size > sp2->size) return (-1); } else { if (sp1->num < sp2->num) return (1); if (sp1->num > sp2->num) return (-1); } return (0); } int comp_rout(const void *p1, const void *p2) { const struct rout * sp1 = *(const struct rout * const *)p1; const struct rout * sp2 = *(const struct rout * const *)p2; if (sflag) { if (sp1->size < sp2->size) return (1); if (sp1->size > sp2->size) return (-1); } else { if (sp1->num < sp2->num) return (1); if (sp1->num > sp2->num) return (-1); } return (0); } int comp_s(const void *p1, const void *p2) { const struct status * sp1 = *(const struct status * const *)p1; const struct status * sp2 = *(const struct status * const *)p2; if (sp1->num < sp2->num) return (1); if (sp1->num > sp2->num) return (-1); return (0); } int comp_r(const void *p1, const void *p2) { const struct rule * sp1 = *(const struct rule * const *)p1; const struct rule * sp2 = *(const struct rule * const *)p2; if (sp1->num < sp2->num) return (1); if (sp1->num > sp2->num) return (-1); return (0); } int comp_rrel(const void *p1, const void *p2) { const struct rrelay * sp1 = *(const struct rrelay * const *)p1; const struct rrelay * sp2 = *(const struct rrelay * const *)p2; if (sp1->num < sp2->num) return (1); if (sp1->num > sp2->num) return (-1); return (0); } /* * Calculate the average daily/hour messages */ void average(struct host *hptr, int *dd, float *ad, int *hh, float *ah) { int fulld; int fullh; int weeks; int hours; int hfday, hfhour; int i; hfday = hptr->fday; hfhour = hptr->fhour; /* integer value of hours: */ fullh = (int)hptr->dtime/3600; fullh++; /* integer value of days: */ fulld = (int)hptr->dtime/(24*3600); fulld++; /* * calculate full weeks: * * days left over from last full week are returned * as int fulld: */ weeks = 0; for (; fulld >= 7; fulld -= 7) weeks++; /* calculate daily averages: */ for (i = 0; i < 7; i++) if (i == hfday && fulld > 0) { ad[i] = (float)dd[i] / ((float)weeks + 1.0); fulld--; hfday++; } else if (weeks) ad[i] = (float)dd[i] / (float)weeks; else ad[i] = (float)dd[i]; /* same calculations for hours: */ hours = 0; for (; fullh >= 24; fullh -= 24) hours++; for (i = 0; i < 24; i++) if (i == hfhour && fullh > 0) { ah[i] = (float)hh[i] / ((float)hours + 1.0); fullh--; hfhour++; } else if (hours) ah[i] = (float)hh[i] / (float)hours; else ah[i] = (float)hh[i]; } /* Strip newline: */ char * stripn(char *s) { char *p; for (p = s; *s != '\n'; s++) ; *s = '\0'; return p; } void error_memory() { fprintf(stderr, "%s: memory allocation failure, errno: %d\n", pname, errno); exit(1); } void copying() { fprintf(stderr, "\nSMA version %s\n\n" , VERSION); fprintf(stderr, "This program is Copyright (c) 2000 - 2003\n" " Jarkko Turkulainen. All rights reserved.\n" "Some parts are " "Copyright (c) 1992, 1993, 1994\n" " Henry Spencer. All rights reserved.\n" "Some parts are " "Copyright (c) 1985, 1987, 1988, 1993, 1994\n" " The Regents of the University of California. " "All rights reserved.\n\n"); exit(0); } void usage() { /* Use stdout - easier to "more" or "less" .. */ fprintf(stdout, "\nSMA version %s\n\n" , VERSION); fprintf(stdout, "usage: %s [OPTIONS] [files...]\n" "OPTIONS are\n" " -A\t\tforce addresses to lower case to help with consistent counts\n" " -a\t\tset the output format as ascii\n" " -b \tbackground color (RGB) of the HTML form\n" " -c\t\tshow copyright information and exit\n" " -C \tset report header as \n" " -D \tanalyse only log entries between dates d1 and d2\n" " -d\t\tprint only the domain portion of email addresses\n" " -f \tuse configuration from instead of default\n" " -F\t\tdo not use default configuration file even if it exists\n" " -h\t\tprint this text and exit\n" " -H \toverride the hostname with \n" " -i\t\tprint ASCII report as HTML comment (requires -w or -O html)\n" " -L \tprocess only lines with syslog tag \n" " -n\t\tdo not print the time distribution\n" " -o \twrite output to \n" " -O \tset output format (ascii/html/clog)\n" " -p\t\tprint current configuration to stdout\n" " -s\t\tsort by tranfers\n" " -q\t\tbe quiet (no error messages)\n" " -v\t\tshow debugging information\n" " -l \tprint top addresses\n" " -r \tprint top relay addresses\n" " -t \tset the internal hash table size (normal/big/huge/a,r)\n" " -w\t\tset the output format as html\n" " files\tlog files\n\n", pname); exit(0); } void dump_config(FILE *handle) { char *p = NULL; char dates[128]; fprintf(handle, " BgColor %s\n", bchar); fprintf(handle, " BounceAddress %s\n", bechar); fprintf(handle, " CaseSensitive %s\n", csflag ? "no" : "yes"); if (cfchar) fprintf(handle, " ClogFormat \"%s\"\n", cfchar); fprintf(handle, " ClogSentOnly %s\n", clsflag ? "yes" : "no"); fprintf(handle, " Comment \"%s\"\n", Cchar); fprintf(handle, " Debug %s\n", vflag ? "yes" : "no"); if (eetime) { strftime(dates, 127, "%Y/%m/%d-%H:%M:%S", localtime(&eetime)); fprintf(handle, " EndTime %s\n", dates); } fprintf(handle, " EnvelopePairs %d\n", epnum); fprintf(handle, " EnvelopeRecipientFilter %s\n", ref ? ref : "*"); fprintf(handle, " EnvelopeRecipients %d\n", lrnum); fprintf(handle, " EnvelopeSenderFilter %s\n", sef ? sef : "*"); fprintf(handle, " EnvelopeSenders %d\n", lnum); if (ftchar) fprintf(handle, " FooterText \"%s\"\n", ftchar); switch(Oflag) { case FORMAT_ASCII: if (!(p = strdup("ascii"))) error_memory(); break; case FORMAT_HTML: if (!(p = strdup("html"))) error_memory(); break; case FORMAT_CLOG: if (!(p = strdup("clog"))) error_memory(); break; } fprintf(handle, " Format %s\n", p); free(p); fprintf(handle, " HashTables %d,%d\n", asize, rsize); if (htchar) fprintf(handle, " HeaderText \"%s\"\n", htchar); if (Hchar) fprintf(handle, " HostName \"%s\"\n", Hchar); fprintf(handle, " IncludeAscii %s\n", iflag ? "yes" : "no"); if (ochar) fprintf(handle, " OutFile \"%s\"\n", ochar); if (plchar) fprintf(handle, " PictureLink \"%s\"\n", plchar); if (ppchar) fprintf(handle, " PictureParameters \"%s\"\n", ppchar); if (pachar) fprintf(handle, " PictureURL %s\n", pachar); fprintf(handle, " PrintGeneralInfo %s\n", pgflag ? "yes" : "no"); fprintf(handle, " PrintRuleset %s\n", rsnum ? "yes" : "no"); fprintf(handle, " PrintStatus %s\n", stnum ? "yes" : "no"); fprintf(handle, " RelayPairs %d\n", rpnum); fprintf(handle, " RelayRecipientFilter %s\n", rrf ? rrf : "*"); fprintf(handle, " RelayRecipients %d\n", rrnum); fprintf(handle, " RelaySenderFilter %s\n", srf ? srf : "*"); fprintf(handle, " RelaySenders %d\n", rnum); fprintf(handle, " RulesetRelays %d\n", rsrnum); fprintf(handle, " ShowUsers %s\n", dflag ? "no" : "yes"); fprintf(handle, " Silent %s\n", qflag ? "yes" : "no"); fprintf(handle, " Sorting %s\n", sflag ? "transfer" : "number"); if (sstime) { strftime(dates, 127, "%Y/%m/%d-%H:%M:%S", localtime(&sstime)); fprintf(handle, " StartTime %s\n", dates); } if (Lchar) fprintf(handle, " SyslogTag %s\n", Lchar); fprintf(handle, " TbColor %s\n", tbchar); }