1 /*
2  * sma -- Sendmail log analyser
3  *
4  * Copyright (c) 2000 - 2003 Jarkko Turkulainen. All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  *
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  *
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  *
17  * THIS SOFTWARE IS PROVIDED BY JARKKO TURKULAINEN ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED.  IN NO EVENT SHALL JARKKO TURKULAINEN BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  *
29  * $Date: 2003/01/01 13:54:00 $
30  */
31 
32 #include "sma.h"
33 
34 void
ascii(FILE * fp)35 ascii(FILE *fp) {
36 	unsigned int j, h;
37 	char *p;
38 	struct host *hptr;
39 
40 	const char *wdtab[] = { "Sunday", "Monday",
41 	  "Tuesday", "Wednesday", "Thursday",
42 	  "Friday", "Saturday" };
43 
44 	const char *hrtab[] = { "00-01", "01-02", "02-03",
45 	  "03-04", "04-05", "05-06", "06-07", "07-08",
46 	  "08-09", "09-10", "10-11", "11-12", "12-13",
47 	  "13-14", "14-15", "15-16", "16-17", "17-18",
48 	  "18-19", "19-20", "20-21", "21-22", "22-23", "23-00" };
49 
50 	curr = localtime(&tval);
51 	p = asctime(curr);
52 	p[strlen(p)-1] = '\0';
53 
54 	fprintf(fp, "\n%s\n", Cchar);
55 	if (htchar)
56 		fprintf(fp, "%s\n", htchar);
57 	else
58 		fprintf(fp, "Generated at %s by SMA, version %s\n",
59 			p, VERSION);
60 	fprintf(fp, "-----------------------------------------------------------------------------\n\n");
61 
62 	for (hptr = first.next; hptr; hptr = hptr->next) {
63 		if (!(hptr->inum) || !(hptr->inum))
64 			continue;
65 		fprintf(fp, "\nServer: %s\n\n", hptr->name);
66 		if (pgflag) {
67 		fprintf(fp, "General information\n");
68 		fprintf(fp, "-----------------------------------------------------------------------------\n");
69 		fprintf(fp, "  %-33s %s", "First log entry", ctime(&hptr->ftime));
70 		fprintf(fp, "  %-33s %s", "Last log entry", ctime(&hptr->ltime));
71 		fprintf(fp, "  %-33s %d\n", "Alias table rebuilds", hptr->alias);
72 		fprintf(fp, "  %-33s %d\n", "Too many hops", hptr->hopc);
73 		fprintf(fp, "  %-33s %d\n", "Mail loops", hptr->lcerror);
74 		fprintf(fp, "  %-33s %d\n", "Other SYSERR", hptr->oserror);
75 		fprintf(fp, "  %-33s %d\n", "Ruleset based rejections", hptr->rule);
76 		fprintf(fp, "  %-33s %d\n\n", "Sendmail daemon restarts", hptr->dstart);
77 
78 
79 		fprintf(fp, "%s%35s\n", "Inbound messages", "Outbound messages");
80 		fprintf(fp, "-----------------------------------------------------------------------------\n");
81 
82 /*
83  * Hm. it seems that Win32 printf cannot handle correctly long's..
84  * This is not the right thing to do, consider some typedef instead..
85  * But hey, I should drop the Win32 support anyway, who uses it?
86  */
87 #ifdef _WIN32
88 		fprintf(fp, "  %-20s %7d", "Total", (int)hptr->inum);
89 		fprintf(fp, "      %-15s %7d\n", "Total", (int)hptr->gonum);
90 		fprintf(fp, "  %-20s %7.2f", "Average size (kB)",
91 			(double)hptr->size/(double)hptr->inum/1000);
92 #else
93 		fprintf(fp, "  %-20s %7ld", "Total", hptr->inum);
94 		fprintf(fp, "      %-15s %7ld\n", "Total", hptr->gonum);
95 		fprintf(fp, "  %-20s %7.2Lf", "Average size (kB)",
96 			hptr->size/(double)hptr->inum/1000);
97 #endif
98 
99 		fprintf(fp, "      %-15s %7d\n", "Sent", hptr->sent);
100 
101 		fprintf(fp, "  %-20s %7.2f", "Messages/hour",
102 			3600*(float)hptr->inum/(float)hptr->dtime);
103 		fprintf(fp, "      %-15s %7d\n", "Deferred", hptr->defe);
104 
105 		fprintf(fp, "  %-20s %7.2f", "Messages/min",
106 			60*(float)hptr->inum/(float)hptr->dtime);
107 		fprintf(fp, "      %-15s %7d\n", "Queued", hptr->queu);
108 
109 		fprintf(fp, "  %-20s %7.2f", "Messages/sec",
110 			(float)hptr->inum/(float)hptr->dtime);
111 		fprintf(fp, "      %-15s %7d\n", "Other error",
112 			hptr->other + hptr->hunk + hptr->uunk + hptr->service);
113 		}
114 
115 		if (epnum) {
116 		fprintf(fp, "\n\nTop envelope pairs\n");
117 		fprintf(fp, "-----------------------------------------------------------------------------\n");
118 		fprintf(fp, "%5s %-45s %6s %10s %7s\n",
119 			"Nr", "Sender/Recipient", "Msgs", "MB", "%");
120 		fprintf(fp, "-----------------------------------------------------------------------------\n");
121 
122 		for (j = 0; j < (MIN(epnum, hptr->edif)); j++) {
123 #ifdef _WIN32
124 		fprintf(fp, "%5d %-40.40s%-5s %6d %10.2f", j+1,
125 			hptr->setab[j]->fname,
126 			(strlen(hptr->setab[j]->fname) >= 40) ? "$" : " ",
127 			hptr->setab[j]->num,
128 			(double)hptr->setab[j]->size/1000000);
129 #else
130 		fprintf(fp, "%5d %-40.40s%-5s %6d %10.2Lf", j+1,
131 			hptr->setab[j]->fname,
132 			(strlen(hptr->setab[j]->fname) >= 40) ? "$" : " ",
133 			hptr->setab[j]->num,
134 			hptr->setab[j]->size/1000000);
135 #endif
136 
137 			if (sflag) {
138 			  fprintf(fp, " %7.2f\n",
139 			   100*(float)hptr->setab[j]->size/(float)hptr->osize);
140 			} else {
141 			  fprintf(fp, " %7.2f\n",
142 			    100*(float)hptr->setab[j]->num/(float)hptr->onum);
143 			}
144 			fprintf(fp, "      %.40s%s", hptr->setab[j]->tname,
145 			  (strlen(hptr->setab[j]->tname) >= 40) ? "$\n" : "\n");
146 		}
147 		}
148 
149 
150 		if (lnum) {
151 		fprintf(fp, "\nTop envelope senders");
152 		if (sef) fprintf(fp, " (filter: %s)\n", sef);
153 		else fprintf(fp, "\n");
154 		fprintf(fp, "-----------------------------------------------------------------------------\n");
155 		fprintf(fp, "%5s %-45s %6s %10s %7s\n",
156 			"Nr", "Sender", "Msgs", "MB", "%");
157 		fprintf(fp, "-----------------------------------------------------------------------------\n");
158 
159 		for (j = 0; j < (MIN(lnum, hptr->idif)); j++) {
160 #ifdef _WIN32
161 		fprintf(fp, "%5d %-40.40s%-5s %6d %10.2f", j+1,
162 			hptr->sitab[j]->name,
163 			(strlen(hptr->sitab[j]->name) >= 40) ? "$" : " ",
164 			hptr->sitab[j]->num,
165 			(double)hptr->sitab[j]->size/1000000);
166 #else
167 		fprintf(fp, "%5d %-40.40s%-5s %6d %10.2Lf", j+1,
168 			hptr->sitab[j]->name,
169 			(strlen(hptr->sitab[j]->name) >= 40) ? "$" : " ",
170 			hptr->sitab[j]->num,
171 			hptr->sitab[j]->size/1000000);
172 #endif
173 
174 			if (sflag) {
175 			  fprintf(fp, " %7.2f\n",
176 			   100*(float)hptr->sitab[j]->size/(float)hptr->isize);
177 			} else {
178 			  fprintf(fp, " %7.2f\n",
179 			    100*(float)hptr->sitab[j]->num/(float)hptr->inum);
180 			}
181 		}
182 		}
183 
184 		if (lrnum) {
185 		fprintf(fp, "\nTop envelope recipients");
186 		if (ref) fprintf(fp, " (filter: %s)\n", ref);
187 		else fprintf(fp, "\n");
188 		fprintf(fp, "-----------------------------------------------------------------------------\n");
189 		fprintf(fp, "%5s %-45s %6s %10s %7s\n",
190 			"Nr", "Recipient", "Msgs", "MB", "%");
191 		fprintf(fp, "-----------------------------------------------------------------------------\n");
192 		for (j = 0; j < (MIN(lrnum, hptr->odif)); j++) {
193 #ifdef _WIN32
194 		fprintf(fp, "%5d %-40.40s%-5s %6d %10.2f", j+1,
195 			hptr->sotab[j]->name,
196 			(strlen(hptr->sotab[j]->name) >= 40) ? "$" : " ",
197 			hptr->sotab[j]->num,
198 			(double)hptr->sotab[j]->size/1000000);
199 #else
200 		fprintf(fp, "%5d %-40.40s%-5s %6d %10.2Lf", j+1,
201 			hptr->sotab[j]->name,
202 			(strlen(hptr->sotab[j]->name) >= 40) ? "$" : " ",
203 			hptr->sotab[j]->num,
204 			hptr->sotab[j]->size/1000000);
205 #endif
206 
207 			if (sflag) {
208 			  fprintf(fp, " %7.2f\n",
209 			   100*(float)hptr->sotab[j]->size/(float)hptr->osize);
210 			} else {
211 			  fprintf(fp, " %7.2f\n",
212 			    100*(float)hptr->sotab[j]->num/(float)hptr->onum);
213 			}
214 		}
215 		}
216 
217 		if (rpnum) {
218 		fprintf(fp, "\n\nTop relay pairs\n");
219 		fprintf(fp, "-----------------------------------------------------------------------------\n");
220 		fprintf(fp, "%5s %-45s %6s %10s %7s\n",
221 			"Nr", "Sender relay/Recipient relay", "Msgs", "MB", "%");
222 		fprintf(fp, "-----------------------------------------------------------------------------\n");
223 
224 		for (j = 0; j < (MIN(rpnum, hptr->rrdif)); j++) {
225 #ifdef _WIN32
226 		fprintf(fp, "%5d %-40.40s%-5s %6d %10.2f", j+1,
227 			hptr->srtab[j]->fname,
228 			(strlen(hptr->srtab[j]->fname) >= 40) ? "$" : " ",
229 			hptr->srtab[j]->num,
230 			(double)hptr->srtab[j]->size/1000000);
231 #else
232 		fprintf(fp, "%5d %-40.40s%-5s %6d %10.2Lf", j+1,
233 			hptr->srtab[j]->fname,
234 			(strlen(hptr->srtab[j]->fname) >= 40) ? "$" : " ",
235 			hptr->srtab[j]->num,
236 			hptr->srtab[j]->size/1000000);
237 #endif
238 			if (sflag) {
239 			  fprintf(fp, " %7.2f\n",
240 			   100*(float)hptr->srtab[j]->size/(float)hptr->osize);
241 			} else {
242 			  fprintf(fp, " %7.2f\n",
243 			    100*(float)hptr->srtab[j]->num/(float)hptr->onum);
244 			}
245 			fprintf(fp, "      %.40s%s", hptr->srtab[j]->tname,
246 			  (strlen(hptr->srtab[j]->tname) >= 40) ? "$\n" : "\n");
247 		}
248 		}
249 
250 
251 		if (rnum) {
252 		fprintf(fp, "\nTop relay addresses, sender");
253 		if (srf) fprintf(fp, " (filter: %s)\n", srf);
254 		else fprintf(fp, "\n");
255 		fprintf(fp, "-----------------------------------------------------------------------------\n");
256 		fprintf(fp, "%5s %-45s %6s %10s %7s\n",
257 			"Nr", "Relay", "Msgs", "MB", "%");
258 		fprintf(fp, "-----------------------------------------------------------------------------\n");
259 
260 		for (j = 0; j < (MIN(rnum, hptr->ridif)); j++) {
261 #ifdef _WIN32
262 		fprintf(fp, "%5d %-40.40s%-5s %6d %10.2f", j+1,
263 			hptr->rsitab[j]->name,
264 			(strlen(hptr->rsitab[j]->name) >= 40) ? "$" : " ",
265 			hptr->rsitab[j]->num,
266 			(double)hptr->rsitab[j]->size/1000000);
267 #else
268 		fprintf(fp, "%5d %-40.40s%-5s %6d %10.2Lf", j+1,
269 			hptr->rsitab[j]->name,
270 			(strlen(hptr->rsitab[j]->name) >= 40) ? "$" : " ",
271 			hptr->rsitab[j]->num,
272 			hptr->rsitab[j]->size/1000000);
273 #endif
274 
275 			if (sflag) {
276 			  fprintf(fp, " %7.2f\n",
277 			   100*(float)hptr->rsitab[j]->size/(float)hptr->isize);
278 			} else {
279 			  fprintf(fp, " %7.2f\n",
280 			    100*(float)hptr->rsitab[j]->num/(float)hptr->rinum);
281 			}
282 
283 		}
284 		}
285 
286 		if (rrnum) {
287 		fprintf(fp, "\nTop relay addresses, recipient");
288 		if (rrf) fprintf(fp, " (filter: %s)\n", rrf);
289 		else fprintf(fp, "\n");
290 		fprintf(fp, "-----------------------------------------------------------------------------\n");
291 		fprintf(fp, "%5s %-45s %6s %10s %7s\n",
292 			"Nr", "Relay", "Msgs", "MB", "%");
293 		fprintf(fp, "-----------------------------------------------------------------------------\n");
294 		for (j = 0; j < (MIN(rrnum, hptr->rodif)); j++) {
295 #ifdef _WIN32
296 		fprintf(fp, "%5d %-40.40s%-5s %6d %10.2f", j+1,
297 			hptr->rsotab[j]->name,
298 			(strlen(hptr->rsotab[j]->name) >= 40) ? "$" : " ",
299 			hptr->rsotab[j]->num,
300 			(double)hptr->rsotab[j]->size/1000000);
301 #else
302 		fprintf(fp, "%5d %-40.40s%-5s %6d %10.2Lf", j+1,
303 			hptr->rsotab[j]->name,
304 			(strlen(hptr->rsotab[j]->name) >= 40) ? "$" : " ",
305 			hptr->rsotab[j]->num,
306 			hptr->rsotab[j]->size/1000000);
307 #endif
308 			if (sflag) {
309 			  fprintf(fp, " %7.2f\n",
310 			   100*(float)hptr->rsotab[j]->size/(float)hptr->osize);
311 			} else {
312 			  fprintf(fp, " %7.2f\n",
313 			    100*(float)hptr->rsotab[j]->num/(float)hptr->ronum);
314 			}
315 		}
316 		}
317 
318 		if (stnum) {
319 		fprintf(fp, "\n\nTop status messages\n");
320 		fprintf(fp, "-----------------------------------------------------------------------------\n");
321 		fprintf(fp, "%5s %7s %6s %s\n",
322 			"Nr", "Msgs", "%", "  Status");
323 		fprintf(fp, "-----------------------------------------------------------------------------\n");
324 		for (j = 0; j < (MIN(stnum, hptr->sdif)); j++) {
325 		fprintf(fp, "%5d %7d %6.2f %s %-52s\n", j+1,
326 			hptr->ssttab[j]->num,
327 			100*(float)hptr->ssttab[j]->num/(float)hptr->onum,
328 			" ", hptr->ssttab[j]->name);
329 		}
330 		}
331 
332 		if (rsnum) {
333 		fprintf(fp, "\n\nTop ruleset rejections\n");
334 		fprintf(fp, "-----------------------------------------------------------------------------\n");
335 		fprintf(fp, "%5s %7s %6s %s\n",
336 			"Nr", "Msgs", "%", rsrnum ? "  Reason / Top relays" : "  Reason");
337 		fprintf(fp, "-----------------------------------------------------------------------------\n");
338 		for (j = 0; j < (MIN(rsnum, hptr->rdif)); j++) {
339 		fprintf(fp, "%5d %7d %6.2f %s %-52s\n", j+1,
340 			hptr->sruletab[j]->num,
341 			100*(float)hptr->sruletab[j]->num/(float)hptr->rule,
342 			" ", hptr->sruletab[j]->name);
343 
344 		if (rsrnum) {
345 		fprintf(fp, "    ------------------------------------------------------------------------\n");
346 		for (h = 0; h < (MIN(rsrnum, hptr->sruletab[j]->reldif)); h++) {
347 		fprintf(fp, "%13d %6.2f %s %s\n",
348 			hptr->sruletab[j]->srrelaytab[h]->num,
349 			100*(float)hptr->sruletab[j]->srrelaytab[h]->num/(float)hptr->sruletab[j]->num,
350 			" ", hptr->sruletab[j]->srrelaytab[h]->name);
351 		}
352 		fprintf(fp, "\n");
353 		}
354 
355 		}
356 		}
357 
358 		if (!nflag) {
359 		fprintf(fp, "\n\n%s%42s\n", "Inbound messages per day", "Outbound messages per day");
360 		fprintf(fp, "-----------------------------------------------------------------------------\n");
361 		fprintf(fp, "%s %-9s %9s %9s %10s %-9s %9s %9s\n",
362 			"  ", "Day", "Total", "Average",
363 			"    ", "Day", "Total", "Average");
364 		fprintf(fp, "-----------------------------------------------------------------------------\n");
365 		for (j = 0; j < 7; j++) {
366 			if (hptr->idd[j])
367 			fprintf(fp, "%s %-9s %9d %9.2f %10s %-9s %9d %9.2f\n",
368 				"  ", wdtab[j], hptr->idd[j], hptr->fidd[j],
369 				"    ", wdtab[j], hptr->odd[j], hptr->fodd[j]);
370 		}
371 
372 		fprintf(fp, "\n\n%s%42s\n", "Inbound messages per hour", "Outbound messages per hour");
373 		fprintf(fp, "-----------------------------------------------------------------------------\n");
374 		fprintf(fp, "%s %-9s %9s %9s %10s %-9s %9s %9s\n",
375 			"  ", "Hour", "Total", "Average",
376 			"    ", "Hour", "Total", "Average");
377 		fprintf(fp, "-----------------------------------------------------------------------------\n");
378 
379 		for (j = 0; j < 24; j++) {
380 			if (hptr->ihh[j]) {
381 			fprintf(fp, "%s %-9s %9d %9.2f %10s %-9s %9d %9.2f\n",
382 				"  ", hrtab[j], hptr->ihh[j], hptr->fihh[j],
383 				"    ", hrtab[j], hptr->ohh[j], hptr->fohh[j]);
384 			}
385 		}
386 
387 	}
388 	}
389 	fprintf(fp, "\n\n-----------------------------------------------------------------------------\n");
390 	if (ftchar)
391 		fprintf(fp, "%s\n", ftchar);
392 	else
393 		fprintf(fp, "Copyright (c) 2000 - 2003 Jarkko Turkulainen."
394 		" All rights reserved.\n");
395 }
396