/*
 * 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");
}
