1 /* 2 ** Modular Logfile Analyzer 3 ** Copyright 2000 Jan Kneschke <jan@kneschke.de> 4 ** 5 ** Homepage: http://www.modlogan.org 6 ** 7 8 This program is free software; you can redistribute it and/or modify 9 it under the terms of the GNU General Public License as published by 10 the Free Software Foundation; either version 2 of the License, or 11 (at your option) any later version, and provided that the above 12 copyright and permission notice is included with all distributed 13 copies of this or derived software. 14 15 This program is distributed in the hope that it will be useful, 16 but WITHOUT ANY WARRANTY; without even the implied warranty of 17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 GNU General Public License for more details. 19 20 You should have received a copy of the GNU General Public License 21 along with this program; if not, write to the Free Software 22 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA 23 24 ** 25 ** $Id: generate.c,v 1.27 2003/06/03 16:35:52 ostborn Exp $ 26 */ 27 28 #include <libintl.h> 29 #include <locale.h> 30 #include <stdlib.h> 31 #include <stdio.h> 32 #include <time.h> 33 #include <math.h> 34 #include <string.h> 35 #include <sys/stat.h> 36 #include <sys/types.h> 37 38 #include "mconfig.h" 39 #include "mstate.h" 40 #include "mlocale.h" 41 #include "mhash.h" 42 #include "mlist.h" 43 #include "mdatatypes.h" 44 #include "mplugins.h" 45 46 #include "plugin_config.h" 47 48 #if 0 49 #define DEBUG_STRREP 50 #endif 51 52 int mplugins_output_text_ippl_generate_monthly_output(mconfig *ext_conf, mstate *state, const char *subpath); 53 int mplugins_output_text_mail_generate_monthly_output(mconfig *ext_conf, mstate *state, const char *subpath); 54 char *put_gap_before( float ); 55 int show_data_stat_ippl(mconfig *ext_conf, FILE *f, mhash *h, int count, int formlenght); 56 mdata_ipplwatchelement **sort_ipplwatchelements( mdata_ipplwatchelement **src, int num); 57 58 mdata_ipplwatchelement **sort_ipplwatchelements( mdata_ipplwatchelement **src, int num ) { 59 int i, ii; 60 mdata_ipplwatchelement **tosort, **sorted; 61 62 if (num<2) 63 return src; 64 65 tosort = malloc( sizeof(mdata_ipplwatchelement *) * num); 66 memcpy( tosort, src, num * sizeof(mdata_ipplwatchelement *)); 67 sorted = malloc( sizeof(mdata_ipplwatchelement *) * num); 68 69 for (ii=0; ii<num; ii++) { 70 int elemaxnum = -1; 71 long countnum = -1; 72 73 for (i=0; i<num; i++) { 74 if (tosort[i] != NULL && 75 tosort[i]->count >= countnum) { 76 countnum = tosort[i]->count; 77 elemaxnum = i; 78 } 79 } 80 81 if (elemaxnum > -1) { 82 sorted[ii] = tosort[elemaxnum]; 83 tosort[elemaxnum] = NULL; 84 } else { 85 fprintf(stderr, "%s.%d: Fatal error: something screwed up in sort!\n", 86 __FILE__, __LINE__ ); 87 } 88 } 89 90 return sorted; 91 } 92 93 int mlist_sumup(mlist *l) { 94 int c = 0; 95 if (!l) return 0; 96 97 while (l) { 98 if (l->data) { 99 c += mdata_get_count(l->data); 100 } 101 l = l->next; 102 } 103 104 return c; 105 } 106 107 long mhash_sumup(mhash *h) { 108 int i, c = 0; 109 if (!h) return 0; 110 111 for ( i = 0; i < h->size; i++) { 112 c += mlist_sumup(h->data[i]->list); 113 } 114 115 return c; 116 } 117 118 mlist * get_next_element(mhash *h) { 119 mlist *ret = NULL; 120 int max = 0, i; 121 122 for ( i = 0; i < h->size; i++) { 123 mlist *l = h->data[i]->list; 124 while (l) { 125 if (l->data) { 126 mdata *data = l->data; 127 128 if ( mdata_get_count(data) > max) { 129 max = mdata_get_count(data); 130 ret = l; 131 } 132 } 133 l = l->next; 134 } 135 } 136 137 if (ret) { 138 mdata_set_count(ret->data, -mdata_get_count(ret->data)); 139 } 140 141 return ret; 142 } 143 144 int cleanup_elements(mhash *h) { 145 int i; 146 for ( i = 0; i < h->size; i++) { 147 mlist *l = h->data[i]->list; 148 while (l) { 149 if (l->data) { 150 mdata *data = l->data; 151 152 mdata_set_count(data, -mdata_get_count(data)); 153 154 } 155 l = l->next; 156 } 157 } 158 159 return 0; 160 } 161 162 int show_visit_path (mconfig *ext_conf, FILE *f, mhash *h, int count) { 163 int i = 0; 164 mlist *l; 165 long sum; 166 167 if (!h) return 0; 168 169 sum = mhash_sumup(h); 170 171 while ((l = get_next_element(h)) && i < count) { 172 if (l->data) { 173 mdata *data = l->data; 174 int c = -mdata_get_count(data); 175 176 i++; 177 178 fprintf(f,"%2d %8d %6.2f %s\n", i, c, c * 100.0 / sum, data->key); 179 } 180 } 181 182 cleanup_elements(h); 183 184 return 0; 185 } 186 187 int show_port_stat_ippl(mconfig *ext_conf, FILE *f, mhash *h, int count) { 188 return show_data_stat_ippl( ext_conf, f, h, count, 5 ); 189 } 190 191 int show_host_stat_ippl(mconfig *ext_conf, FILE *f, mhash *h, int count) { 192 return show_data_stat_ippl( ext_conf, f, h, count, 15 ); 193 } 194 195 int show_data_stat_ippl(mconfig *ext_conf, FILE *f, mhash *h, int count, int formlength) { 196 int i = 0; 197 mlist *l; 198 long sum; 199 200 if (!h) return 0; 201 202 sum = mhash_sumup(h); 203 204 while ((l = get_next_element(h)) && i < count) { 205 if (l->data) { 206 mdata *data = l->data; 207 int c = -mdata_get_count(data); 208 209 i++; 210 211 fprintf(f, "| %2d | %8d | %s%3.2f | %*s |\n", i, c, 212 put_gap_before( c * 100.0 / sum ), 213 c * 100.0 / sum, formlength, data->key); 214 } 215 } 216 217 cleanup_elements(h); 218 219 return 0; 220 } 221 222 int mplugins_output_text_generate_monthly_output(mconfig *ext_conf, mstate *state, const char *subpath) { 223 if (state == NULL) return -1; 224 if (state->ext == NULL) return -1; 225 226 switch (state->ext_type ) { 227 case M_STATE_TYPE_MAIL: 228 return mplugins_output_text_mail_generate_monthly_output(ext_conf, state, subpath); 229 case M_STATE_TYPE_IPPL: 230 return mplugins_output_text_ippl_generate_monthly_output(ext_conf, state, subpath); 231 default: 232 return -1; 233 } 234 } 235 236 char* strrep( char *torep, int num ) { 237 int resize; 238 char *result; 239 240 if (!num) return NULL; 241 242 if (num==1) { 243 return strdup( torep ); 244 } 245 246 #ifdef DEBUG_STRREP 247 fprintf( stderr, "Calculating result size..." ); 248 #endif 249 resize = num * strlen( torep ) + 1; 250 #ifdef DEBUG_STRREP 251 fprintf( stderr, "done, %d.\nAllocating result memory and filling w/ original content...", resize ); 252 #endif 253 /* we use strn* because we don't want buffer overrun for 254 * extremely _long_ strings.. (Miham) */ 255 result = strncpy( malloc( resize ), torep, (resize-1) / num ); 256 result[1] = 0; 257 #ifdef DEBUG_STRREP 258 fprintf( stderr, "done, '%s'.\nEntering while-loop...", result ); 259 #endif 260 261 while( --num ) { 262 #ifdef DEBUG_STRREP 263 fprintf( stderr, "done.\nConcatenating to '%s'...", result ); 264 #endif 265 result = strncat( result, torep, (resize-1) / num ); 266 } 267 268 #ifdef DEBUG_STRREP 269 fprintf( stderr, "done.\nResult is '%s'.\nReturning result and leaving strrep...\n", result ); 270 #endif 271 return result; 272 } 273 274 char *put_gap_before( float percent ) { 275 if (percent < 10.0 ) 276 return " "; 277 if (percent < 100.0) 278 return " "; 279 return ""; 280 } 281 282 int mplugins_output_text_ippl_generate_monthly_output(mconfig *ext_conf, mstate *state, const char *subpath) { 283 FILE *f = NULL; 284 char filename[255]; 285 config_output *conf = ext_conf->plugin_conf; 286 mstate_ippl *staipl = NULL; 287 marray_ippl sum; 288 int i; 289 int pad; 290 char *padstr; 291 long psum; 292 293 if (state == NULL) return -1; 294 if (state->ext == NULL) return -1; 295 if (state->ext_type != M_STATE_TYPE_IPPL) return -1; 296 297 staipl = state->ext; 298 299 if (subpath) { 300 sprintf(filename, "%s/%s/", 301 conf->outputdir ? conf->outputdir : ".", 302 subpath); 303 mkdir(filename, 0755); 304 } 305 306 sprintf(filename, "%s%s%s/index-%04d%02d.txt", 307 conf->outputdir ? conf->outputdir : ".", 308 subpath ? "/" : "", 309 subpath ? subpath : "", 310 state->year, state->month 311 ); 312 313 if (!(f = fopen(filename, "w"))) { 314 return -1; 315 } 316 317 /* Main title */ 318 pad = 80 - 19 - strlen( conf->hostname ); 319 if (pad > 1) { 320 pad /= 2; 321 padstr = strrep( strdup(" "), pad); 322 } else { 323 padstr = 0; 324 } 325 326 fprintf(f, "\n%s+----------------%s-+\n", padstr, strrep( strdup("-"), strlen( conf->hostname ) ) ); 327 fprintf(f, "%s| ippl-stats for %s |\n", padstr, conf->hostname); 328 fprintf(f, "%s+----------------%s-+\n\n", padstr, strrep( strdup("-"), strlen( conf->hostname ) ) ); 329 330 /* hourly stat */ 331 sum.packets = 0; 332 sum.hosts = 0; 333 sum.ports = 0; 334 sum.portscannum = 0; 335 336 fprintf(f, "\n+------------------------------------------------+\n"); 337 fprintf(f, "| Hourly statistics for packets, hosts and ports |\n"); 338 fprintf(f, "+-------+----------+----------+----------+-------+--+\n"); 339 fprintf(f,"| %5s | %8s | %8s | %8s | %8s |\n", 340 "hour", 341 "packets", 342 "hosts", 343 "ports", 344 "portscan"); 345 fprintf(f, "+-------+----------+----------+----------+----------+\n"); 346 for ( i = 0; i < 24; i++) { 347 fprintf(f,"| %5d | %8ld | %8ld | %8ld | %8ld |\n", 348 i, 349 staipl->hours[i].packets, 350 staipl->hours[i].hosts, 351 staipl->hours[i].ports, 352 staipl->hours[i].portscannum 353 ); 354 sum.packets += staipl->hours[i].packets; 355 sum.hosts += staipl->hours[i].hosts; 356 sum.ports += staipl->hours[i].ports; 357 sum.portscannum += staipl->hours[i].portscannum; 358 } 359 360 fprintf(f, "+-------+----------+----------+----------+----------+\n"); 361 fprintf(f,"| %5s | %8ld | %8ld | %8ld | %8ld |\n", 362 "TOTAL", 363 sum.packets, 364 sum.hosts, 365 sum.ports, 366 sum.portscannum 367 ); 368 369 fprintf(f, "+-------+----------+----------+----------+----------+\n\n\n"); 370 371 sum.packets = 0; 372 sum.hosts = 0; 373 sum.ports = 0; 374 sum.portscannum = 0; 375 376 /* Daily stat */ 377 fprintf(f, "+-----------------------------------------------+\n"); 378 fprintf(f, "| Daily statistics for packets, hosts and ports |\n"); 379 fprintf(f, "+-------+----------+----------+----------+------+---+\n"); 380 fprintf(f,"| %5s | %8s | %8s | %8s | %8s |\n", 381 "day", 382 "packets", 383 "hosts", 384 "ports", 385 "portscan"); 386 for ( i = 0; i < 31; i++) { 387 fprintf(f,"| %5d | %8ld | %8ld | %8ld | %8ld |\n", 388 i, 389 staipl->days[i].packets, 390 staipl->days[i].hosts, 391 staipl->days[i].ports, 392 staipl->days[i].portscannum 393 ); 394 sum.packets += staipl->days[i].packets; 395 sum.hosts += staipl->days[i].hosts; 396 sum.ports += staipl->days[i].ports; 397 sum.portscannum += staipl->days[i].portscannum; 398 } 399 400 fprintf(f, "+-------+----------+----------+----------+----------+\n"); 401 fprintf(f,"| %5s | %8ld | %8ld | %8ld | %8ld |\n", 402 "TOTAL", 403 sum.packets, 404 sum.hosts, 405 sum.ports, 406 sum.portscannum 407 ); 408 fprintf(f, "+-------+----------+----------+----------+----------+\n\n\n"); 409 410 /* packettypes */ 411 fprintf(f, "+-----------------+\n"); 412 fprintf(f, "| Packets by type |\n"); 413 psum = staipl->protocols.icmp + 414 staipl->protocols.udp + 415 staipl->protocols.tcp + 416 staipl->protocols.other; 417 fprintf(f, "+-------+---------+--------+\n"); 418 fprintf(f, "| Type | Number | %% |\n"); 419 fprintf(f, "+-------+---------+--------+\n"); 420 fprintf(f, "| %5s | %7ld | %s%3.2f |\n", "ICMP", staipl->protocols.icmp, 421 put_gap_before( 100.0 * staipl->protocols.icmp / psum ), 422 100.0 * staipl->protocols.icmp / psum); 423 fprintf(f, "| %5s | %7ld | %s%3.2f |\n", "TCP", staipl->protocols.tcp, 424 put_gap_before( 100.0 * staipl->protocols.tcp / psum ), 425 100.0 * staipl->protocols.tcp / psum); 426 fprintf(f, "| %5s | %7ld | %s%3.2f |\n", "UDP", staipl->protocols.udp, 427 put_gap_before( 100.0 * staipl->protocols.udp / psum ), 428 100.0 * staipl->protocols.udp / psum); 429 fprintf(f, "| %5s | %7ld | %s%3.2f |\n", "OTHER", staipl->protocols.other, 430 put_gap_before( 100.0 * staipl->protocols.other / psum ), 431 100.0 * staipl->protocols.other / psum); 432 fprintf(f, "+-------+---------+--------+\n\n\n"); 433 434 /* ipopts stat */ 435 fprintf(f, "+--------------------+\n"); 436 fprintf(f, "| Packets by IP opts |\n"); 437 psum = staipl->ipopts.has_ipopts + staipl->ipopts.has_no_ipopts; 438 fprintf(f, "+-------------+------+--+--------+\n"); 439 fprintf(f, "| Has IP-opts | Number | %% |\n"); 440 fprintf(f, "+-------------+---------+--------+\n"); 441 fprintf(f, "| %11s | %7ld | %s%3.2f |\n", "Yes", staipl->ipopts.has_ipopts, 442 put_gap_before( 100.0 * staipl->ipopts.has_ipopts / psum ), 443 100.0 * staipl->ipopts.has_ipopts / psum); 444 fprintf(f, "| %11s | %7ld | %s%3.2f |\n", "No", staipl->ipopts.has_no_ipopts, 445 put_gap_before( 100.0 * staipl->ipopts.has_no_ipopts / psum ), 446 100.0 * staipl->ipopts.has_no_ipopts / psum); 447 fprintf(f, "+-------------+---------+--------+\n\n\n"); 448 449 /* source hosts */ 450 fprintf(f, "+--------------+\n"); 451 fprintf(f, "| source hosts |\n"); 452 fprintf(f, "+----+---------++--------+-----------------+\n"); 453 fprintf(f, "| # | %8s | %% | %15s |\n", "number", "IP" ); 454 fprintf(f, "+----+----------+--------+-----------------+\n"); 455 show_host_stat_ippl(ext_conf, f, staipl->source_ips, 20); 456 fprintf(f, "+----+----------+--------+-----------------+\n\n\n"); 457 458 /* destination ports */ 459 fprintf(f, "+-------------------+\n"); 460 fprintf(f, "| destination ports |\n"); 461 fprintf(f, "+----+----------+---+----+-------+\n"); 462 fprintf(f, "| # | %8s | %% | %5s |\n", "number", "port" ); 463 fprintf(f, "+----+----------+--------+-------+\n"); 464 show_port_stat_ippl(ext_conf, f, staipl->destination_ports, 20); 465 fprintf(f, "+----+----------+--------+-------+\n\n\n"); 466 467 /* fully remembered source hosts, if any */ 468 if (mhash_count( staipl->watched_shosts )) { 469 int wi; 470 471 mdata **watches = mhash_sorted_to_marray(staipl->watched_shosts,M_SORTBY_KEY,M_SORTDIR_ASC); 472 473 fprintf(f, "+----------------------+\n"); 474 fprintf(f, "| Watched source hosts |\n"); 475 fprintf(f, "+-------+--------------+----------------------+\n"); 476 fprintf(f, "| # NUM | Source host |\n"); 477 fprintf(f, "+-------+--------------------------+----------+\n"); 478 fprintf(f, "| Port | Last timestamp | Count |\n"); 479 fprintf(f, "+=======+==========================+==========+\n"); 480 481 for (wi = 0; watches[wi] != NULL; wi++) { 482 int wj; 483 char *ctimedata; 484 mdata *actw = watches[wi]; 485 mdata_ipplwatchelement **actcs = sort_ipplwatchelements(actw->data.ipplwatch->watches, actw->data.ipplwatch->count); 486 487 fprintf(f, "| %4d. | %35s |\n", wi+1, actw->key ); 488 fprintf(f, "+-------+--------------------------+----------+\n"); 489 490 491 for (wj = 0; 492 wj < actw->data.ipplwatch->count && actcs[wj] != NULL; 493 wj++ ) { 494 ctimedata = malloc(45); 495 if( !strftime(ctimedata, 44, "%c", localtime( &(actcs[wj]->timestamp) ) ) ) { 496 fprintf(stderr, "%s.%d: Time formating failed!\n", __FILE__, __LINE__); 497 } 498 499 fprintf(f, "| %5s | %24s | %8ld |\n", actcs[wj]->data, 500 ctimedata, actcs[wj]->count ); 501 free(ctimedata); 502 } 503 free(actcs); 504 fprintf(f, "+=======+==========================+==========+\n"); 505 } 506 fprintf(f,"\n\n"); 507 } 508 509 /* fully remembered destination ports, if any */ 510 if (mhash_count( staipl->watched_dports )) { 511 int wi; 512 513 mdata **watches = mhash_sorted_to_marray(staipl->watched_dports,M_SORTBY_KEY,M_SORTDIR_ASC); 514 515 fprintf(f, "+---------------------------+\n"); 516 fprintf(f, "| Watched destination ports |\n"); 517 fprintf(f, "+-----------------+---------+---------------------------+\n"); 518 fprintf(f, "| # NUM | Destination port |\n"); 519 fprintf(f, "+-----------------+--------------------------+----------+\n"); 520 fprintf(f, "| Host | Last timestamp | Count |\n"); 521 fprintf(f, "+=================+==========================+==========+\n"); 522 523 for (wi = 0; watches[wi] != NULL; wi++) { 524 int wj; 525 char *ctimedata; 526 mdata *actw = watches[wi]; 527 528 mdata_ipplwatchelement **actcs = sort_ipplwatchelements(actw->data.ipplwatch->watches, actw->data.ipplwatch->count); 529 530 fprintf(f, "| %14d. | %35s |\n", wi+1, actw->key ); 531 fprintf(f, "+-----------------+--------------------------+----------+\n"); 532 533 for (wj = 0; 534 wj < actw->data.ipplwatch->count && actcs[wj] != NULL; 535 wj++ ) { 536 ctimedata = malloc(45); 537 if( !strftime(ctimedata, 44, "%c", localtime( &(actcs[wj]->timestamp) ) ) ) { 538 fprintf(stderr, "%s.%d: Time formating failed!\n", __FILE__, __LINE__); 539 } 540 541 fprintf(f, "| %15s | %24s | %8ld |\n", actcs[wj]->data, 542 ctimedata, actcs[wj]->count); 543 free(ctimedata); 544 } 545 free(actcs); 546 fprintf(f, "+=================+==========================+==========+\n"); 547 } 548 fprintf(f,"\n\n"); 549 } 550 551 fclose(f); 552 553 return 0; 554 } 555 556 557 int mplugins_output_text_mail_generate_monthly_output(mconfig *ext_conf, mstate *state, const char *subpath) { 558 FILE *f = NULL; 559 char filename[255]; 560 config_output *conf = ext_conf->plugin_conf; 561 mstate_mail *stamail = NULL; 562 marray_mail sum; 563 int i,j; 564 565 if (state == NULL) return -1; 566 if (state->ext == NULL) return -1; 567 if (state->ext_type != M_STATE_TYPE_MAIL) return -1; 568 569 stamail = state->ext; 570 571 if (subpath) { 572 sprintf(filename, "%s/%s/", 573 conf->outputdir ? conf->outputdir : ".", 574 subpath); 575 mkdir(filename, 0755); 576 } 577 578 sprintf(filename, "%s%s%s/index-%04d%02d.txt", 579 conf->outputdir ? conf->outputdir : ".", 580 subpath ? "/" : "", 581 subpath ? subpath : "", 582 state->year, state->month 583 ); 584 585 if (!(f = fopen(filename, "w"))) { 586 return -1; 587 } 588 589 sum.incoming_mails = 0; 590 sum.outgoing_mails = 0; 591 sum.incoming_bytes = 0; 592 sum.outgoing_bytes = 0; 593 594 fprintf(f, "Oo. mailstats for %s.oO\n\n", conf->hostname); 595 596 fprintf(f, ".-= mailcount and traffic by day =-.\n"); 597 fprintf(f," %5s %10s %10s %10s %10s\n", 598 "hour", 599 "mail-in", 600 "mail-out", 601 "bytes-in", 602 "bytes-out"); 603 for ( i = 0; i < 24; i++) { 604 fprintf(f," %5d %10ld %10ld %10ld %10ld\n", 605 i, 606 stamail->hours[i].incoming_mails, 607 stamail->hours[i].outgoing_mails, 608 stamail->hours[i].incoming_bytes, 609 stamail->hours[i].outgoing_bytes 610 ); 611 sum.incoming_mails += stamail->hours[i].incoming_mails; 612 sum.outgoing_mails += stamail->hours[i].outgoing_mails; 613 sum.incoming_bytes += stamail->hours[i].incoming_bytes; 614 sum.outgoing_bytes += stamail->hours[i].outgoing_bytes; 615 } 616 617 fprintf(f," %5s %10ld %10ld %10ld %10ld\n", 618 "sum", 619 sum.incoming_mails, 620 sum.outgoing_mails, 621 sum.incoming_bytes, 622 sum.outgoing_bytes 623 ); 624 625 fprintf(f, "\n.-= mailcount and traffic by hour =-.\n"); 626 sum.incoming_mails = 0; 627 sum.outgoing_mails = 0; 628 sum.incoming_bytes = 0; 629 sum.outgoing_bytes = 0; 630 fprintf(f," %5s %10s %10s %10s %10s\n", 631 "day", 632 "mail-in", 633 "mail-out", 634 "bytes-in", 635 "bytes-out"); 636 for ( i = 0; i < 31; i++) { 637 fprintf(f," %5d %10ld %10ld %10ld %10ld\n", 638 i, 639 stamail->days[i].incoming_mails, 640 stamail->days[i].outgoing_mails, 641 stamail->days[i].incoming_bytes, 642 stamail->days[i].outgoing_bytes 643 ); 644 sum.incoming_mails += stamail->days[i].incoming_mails; 645 sum.outgoing_mails += stamail->days[i].outgoing_mails; 646 sum.incoming_bytes += stamail->days[i].incoming_bytes; 647 sum.outgoing_bytes += stamail->days[i].outgoing_bytes; 648 } 649 650 fprintf(f," %5s %10ld %10ld %10ld %10ld\n", 651 "sum", 652 sum.incoming_mails, 653 sum.outgoing_mails, 654 sum.incoming_bytes, 655 sum.outgoing_bytes 656 ); 657 658 fprintf(f, "\n.-= mails by sender =-.\n"); 659 show_visit_path (ext_conf, f, stamail->sender, 20); 660 661 fprintf(f, "\n.-= mails by receipient =-.\n"); 662 show_visit_path (ext_conf, f, stamail->receipient, 20); 663 664 fprintf(f, "\n.-= queuepolution =-.\n"); 665 fprintf(f, "%s %s %s %s %s %s %s %s\n", 666 "day", "day", 667 "local-cur", "local-max", 668 "remote-cur", "remote-cur", 669 "deliver-cur", "queue-cur"); 670 for (i = 0; i < 31; i++) { 671 for (j = 0; j < 24; j++) { 672 if (stamail->qstat[i][j].count) { 673 fprintf(f, "%5d %3d %9.0f %9.0f %10.0f %10.0f %11.0f %9.0f\n", 674 i+1, 675 j, 676 stamail->qstat[i][j].local_cur / stamail->qstat[i][j].count, 677 stamail->qstat[i][j].local_max / stamail->qstat[i][j].count, 678 stamail->qstat[i][j].remote_cur / stamail->qstat[i][j].count, 679 stamail->qstat[i][j].remote_max / stamail->qstat[i][j].count, 680 stamail->qstat[i][j].deliver_cur / stamail->qstat[i][j].count, 681 stamail->qstat[i][j].queue_cur / stamail->qstat[i][j].count 682 ); 683 } 684 } 685 } 686 687 fclose(f); 688 689 return 0; 690 691 } 692 693 int mplugins_output_generate_history_output(mconfig *ext_conf, mlist *history, const char *subpath) { 694 695 return 0; 696 } 697