home *** CD-ROM | disk | FTP | other *** search
/ NetNews Usenet Archive 1993 #1 / NN_1993_1.iso / spool / comp / lang / perl / 7767 < prev    next >
Encoding:
Text File  |  1993-01-12  |  13.5 KB  |  612 lines

  1. Newsgroups: comp.lang.perl
  2. Path: sparky!uunet!haven.umd.edu!decuac!pa.dec.com!engage.pko.dec.com!e2big.mko.dec.com!jrdzzz.jrd.dec.com!jrd.dec.com!doi
  3. From: doi@jrd.dec.com (Hitoshi Doi)
  4. Subject: Re: Wanted: script for mailstat
  5. Message-ID: <C0pv5u.488@jrd.dec.com>
  6. Sender: usenet@jrd.dec.com (USENET News System)
  7. Nntp-Posting-Host: usagi.jrd.dec.com
  8. Organization: DEC Japan Research and Development Center
  9. References:  <vhc.726780735@abacus.hgs.se>
  10. Date: Tue, 12 Jan 1993 01:08:17 GMT
  11. Lines: 599
  12.  
  13. In article <vhc.726780735@abacus.hgs.se>, vhc@abacus.hgs.se (Mikael Larsson) writes:
  14. # I am looking for a good perl-script that makes a nice-looking toplist of 
  15. # the users who gets and sends mots mails on this machine.
  16.  
  17. This is what I use.  It isn't be 100% accurate..
  18. Running mstat on my machine says:
  19.  
  20. usagi.jrd.dec.com> mstat -all
  21. mail summary for usagi.jrd.dec.com
  22.  
  23. from              count      bytes
  24. ---------------  ------  ---------
  25. JRD                  23      68473
  26. DEC                   5      18784
  27. non-DEC              22      62870
  28. ---------------  ------  ---------
  29. total                50     150127
  30.  
  31. from                   count      bytes
  32. --------------------  ------  ---------
  33.             \@.*.edu       5      20202
  34.             \@.*.org       3       9997
  35.             \@.*.com       1        781
  36.              \@.*.jp      13      31890
  37. --------------------  ------  ---------
  38.  
  39.                    sent              received
  40. local user         mails      bytes  mails      bytes
  41. -----------------  -----  ---------  -----  ---------
  42.               doi      0          0     49     148520
  43. -----------------  -----  ---------  -----  ---------
  44.                        0          0     49     148520
  45.  
  46. Here's the program.
  47.  
  48. #! /usr/local/bin/perl
  49. #
  50. #    $Id: mstat,v 1.24 92/12/03 11:15:31 doi Exp $
  51. #
  52. #    mstat - get local mail statistics
  53. #
  54. #    this program reads the system mail log to calculate some
  55. #    mail statistics.
  56. #    - it doesn't work 100% percent correct for (cont) lines.
  57. #    - there may be some DEC specific stuff in here.
  58. #    - you should edit the first few lines to match your system.
  59. #    - you should edit the list of domains to match your requirements.
  60. #
  61. #    original hack by Hitoshi Doi (doi@jrd.dec.com), 1991/03/03
  62. #    this program is public domain.  do whatever you wish with it.
  63. #    this program is offered "as is".  there is no warrantee.
  64. #
  65. #    ---------------------------------------------------------------
  66. #    modifications
  67. #    1991/04/01    Hitoshi Doi
  68. #        added options to print out specific stats
  69. #        -totalonly, -useronly, -hostname
  70. #
  71. #    1991/05/17    Hitoshi Doi
  72. #        some minor bugs fixes to make is more correct
  73. #
  74. #    1991/08/27    Hitoshi Doi
  75. #        more minor fixes to make output correct
  76. #
  77. #    1991/10/09    Hitoshi Doi
  78. #        added option to calculate stats for certain domains
  79. #
  80. #    1992/01/08    Hitoshi Doi
  81. #        sort users
  82. #        added -site option
  83. #
  84. #    1992/10/22    Hitoshi Doi
  85. #        SunOS support
  86. #
  87. #    1992/12/03    Hitoshi Doi
  88. #        modified calculation of stats for listed domains
  89. #    ---------------------------------------------------------------
  90.  
  91.     #
  92.     # local system specific stuff
  93.     #
  94.     $company_name = 'DEC';            # company name (for summary)
  95.     $company_addr = '\@.*.dec.com';        # company address (for match)
  96.     $localsite = 'JRD';            # local sub-domain
  97.  
  98.     chop ($localhost = `hostname`);
  99.     chop ($uname = `uname`);
  100.     $me = $0;
  101.     $me =~ s/.*\///;
  102.  
  103.     if ($uname =~ m/osf1/i) {
  104.         $syslog = "/var/adm/syslog/mail.log";    # OSF/1
  105.     }
  106.     elsif ($uname =~ m/ultrix/i) {
  107.         $syslog = "/var/spool/mqueue/syslog";    # ULTRIX
  108.     }
  109.     elsif ($uname =~ m/sunos/i) {
  110.         $syslog = "/var/log/syslog";        # SunOS
  111.     }
  112.  
  113.     $verbose = 0;
  114.     $calc_total = 1;
  115.     $calc_user = 0;
  116.     $calc_from = 0;
  117.     while ($aa = shift(@ARGV)) {
  118.         if ($aa =~ m/-stdin/i) {
  119.             $fdin = STDIN;
  120.             $syslog = "";
  121.         }
  122.         elsif ($aa =~ m/-verbose/i) {
  123.             $verbose = 1;
  124.         }
  125.         elsif ($aa =~ m/-hostname/i) {
  126.             $aa = shift(@ARGV);
  127.             $localhost = $aa;
  128.         }
  129.         elsif ($aa =~ m/-site/i) {
  130.             $aa = shift(@ARGV);
  131.             $localsite = $aa;
  132.         }
  133.         elsif ($aa =~ m/-user/i) {
  134.             $calc_user = 1;
  135.         }
  136.         elsif ($aa =~ m/-from/i) {
  137.             $calc_from = 1;
  138.         }
  139.         elsif ($aa =~ m/-nototal/i) {
  140.             $calc_total = 0;
  141.         }
  142.         elsif ($aa =~ m/-all/i) {
  143.             $calc_from = 1;
  144.             $calc_user = 1;
  145.         }
  146.         elsif ($aa =~ m/-help/i) {
  147.             print "
  148. $me - get local mail statistics
  149.  
  150. usage: $me [options] [syslog]
  151. options: -verbose            give lots of details
  152.          -hostname host      set the hostname
  153.          -site site          set the local site [default = $localsite]
  154.          -stdin              take the syslog information from stdin
  155.          -user               print out the local user information
  156.          -from               calculate from stats per various domains
  157.          -all                -from|-user
  158. the default syslog is $syslog
  159. ";
  160.             exit(0);
  161.         }
  162.         else {
  163.             $syslog = $aa;
  164.         }
  165.     }
  166.     if ($syslog) {
  167.         if (!open(S, "<$syslog")) {
  168.             print "$me: can't open $syslog\n";
  169.             exit(1);
  170.         }
  171.         $fdin = S;
  172.     }
  173.  
  174.     #
  175.     # if we are counting the stats from various domains,
  176.     # initialize the from stats.
  177.     # the $site_code[$i] should be the expression for the domain.
  178.     # if $site_noprint[$i] exists, this site will be counted,
  179.     #  but not displayed in the report.
  180.     #
  181.     if ($calc_from) {
  182.         $site_total = 0;
  183.         $site_code[$site_total++] = '\@.*.edu';
  184.         $site_code[$site_total++] = '\@.*.org';
  185.         $site_noprint[$site_total] = 1;
  186.         $site_code[$site_total++] = '\@.*.dec.com';
  187.         $site_code[$site_total++] = '\@.*.com';
  188.         $site_code[$site_total++] = '\@.*.jp';
  189.         for ($i = 0; $i < $site_total; $i++) {
  190.             $site_ct[$i] = 0;
  191.             $site_bytes[$i] = 0;
  192.         }
  193.     }
  194.  
  195.     $localname = $localhost;
  196.     $localname =~ s/\..*//;
  197.     $localdomain = $localhost;
  198.     $localdomain =~ s/[a-z0-9_]+\.//i;
  199.     #
  200.     # go through the syslog file and fill in the data
  201.     #  @mails, $mailct, @froms, @sizes, @tos
  202.     #
  203.     $mailct = 0;
  204.     while ($l = <$fdin>) {
  205.         next if (!($l =~ m/sendmail/i));
  206.  
  207.         chop($l);
  208.         if ($l =~ m/message-id=\</i) {
  209.             $mails[$mailct++] = do get_id($l);
  210.         }
  211.         elsif ($l =~ m/from=/i) {
  212.             if (($mi = do find_mail(do get_id($l))) < 0) {
  213.                 next;
  214.             }
  215.             $sizes[$mi] = do get_size($l);
  216.             $froms[$mi] = do get_from($l);
  217.         }
  218.         elsif (($l =~ m/to=/i) && !($l =~ m/deffered:/i)) {
  219.             if (($mi = do find_mail(do get_id($l))) < 0) {
  220.                 next;
  221.             }
  222.             $to = do get_to($l);
  223.             if ($tos[$mi]) {
  224.                 $tos[$mi] .= "\t$to";
  225.             }
  226.             else {
  227.                 $tos[$mi] = "$to";
  228.             }
  229.         }
  230.     }
  231.     if ($syslog) {
  232.         close(S);
  233.     }
  234.     #
  235.     # if verbose, print info on all mail
  236.     #
  237.     if ($verbose) {
  238.         for ($i = 0; $i < $mailct; $i++) {
  239.             print "$mails[$i]: $froms[$i] ($sizes[$i]) -> ";
  240.             print "$tos[$i]\n";
  241.         }
  242.     }
  243.  
  244.     #
  245.     # find mail sent by local users
  246.     #  @lusers, $luserct, @lumct, @lumbytes, $locct, $locbytes
  247.     # find mail sent to local users
  248.     #  @tumct, @tumbytes, $tocct, $tocbytes
  249.     # get stats about mail from local sites, DEC, non-DEC
  250.     #
  251.     $totbytes = 0;
  252.     $luserct = 0;
  253.     $locct = 0;
  254.     $locbytes = 0;
  255.     $tocct = 0;
  256.     $tocbytes = 0;
  257.     $sitct = 0;
  258.     $sitbytes = 0;
  259.     $decct = 0;
  260.     $decbytes = 0;
  261.     #
  262.     # process each mail
  263.     #
  264.     for ($i = 0; $i < $mailct; $i++) {
  265.         $totbytes += int($sizes[$i]);
  266.         #
  267.         # from local user
  268.         #
  269.         if ($froms[$i] && !($froms[$i] =~ m/\@/)) {
  270.             if (($uid = do find_luser($froms[$i])) < 0) {
  271.                 $uid = $luserct;
  272.                 $lusers[$luserct++] = $froms[$i];
  273.             }
  274.             $lumct[$uid]++;
  275.             $lumbytes[$uid] += int($sizes[$i]);
  276.             $locct++;
  277.             $locbytes += int($sizes[$i]);
  278.         }
  279.         #
  280.         # to local user
  281.         #
  282.         @tt = split(/\t/, $tos[$i]);
  283.         to_user: foreach $tl (@tt) {
  284.             $tu = $tl;
  285.             if ($tl =~ m/\@/) {
  286.                 $th = $tl;
  287.                 $th =~ s/.*\@//;
  288.                 #
  289.                 # to match local user..
  290.                 # user@localdomain or user@localhost.domain
  291.                 #
  292.                 if ($th ne $localdomain) {
  293.                     $th =~ s/\..*//;
  294.                     next to_user if ($th ne $localname);
  295.                 }
  296.                 $tu = $tl;
  297.                 $tu =~ s/\@.*//;
  298.             }
  299.             #
  300.             # local users shouldn't have period (.) or (!)
  301.             #
  302.             next to_user if ($tu =~ m/\./);
  303.             next to_user if ($tu =~ m/\!/);
  304.             $tu =~ s/^[ ]+//;
  305.             $tu =~ s/[ ]+$//;
  306.             next to_user if (!$tu);
  307.  
  308.             if (($uid = do find_luser($tu)) < 0) {
  309.                 $uid = $luserct;
  310.                 $lusers[$luserct++] = $tu;
  311.             }
  312.             $tumct[$uid]++;
  313.             $tumbytes[$uid] += int($sizes[$i]);
  314.             $tocct++;
  315.             $tocbytes += int($sizes[$i]);
  316.         }
  317.         #
  318.         # from local hosts or same company
  319.         #
  320.         if (!($froms[$i] =~ m/\@/) || ($froms[$i] =~ m/$localsite/i)) {
  321.             $sitct++;
  322.             $sitbytes += int($sizes[$i]);
  323.         }
  324.         elsif ($froms[$i] =~ m/$company_addr/i) {
  325.             $decct++;
  326.             $decbytes += int($sizes[$i]);
  327.         }
  328.         #
  329.         # from certain domains
  330.         #
  331.         if ($calc_from) {
  332.             for ($j = 0; $j < $site_total; $j++) {
  333.                 if ($froms[$i] =~ m/$site_code[$j]/i) {
  334.                     $site_ct[$j]++;
  335.                     $site_bytes[$j] += int($sizes[$i]);
  336.                     last;
  337.                 }
  338.             }
  339.         }
  340.     }
  341.     #
  342.     # print out summaries
  343.     #
  344.     print "mail summary for $localhost\n";
  345.     if ($calc_total) {
  346.         print "\n";
  347.         print "from              count      bytes\n";
  348.         print "---------------  ------  ---------\n";
  349.         printf "%-17s%6d%11d\n", $localsite, $sitct, $sitbytes;
  350.         printf "%-17s%6d%11d\n", $company_name, $decct, $decbytes;
  351.         printf "non-%-13s%6d%11d\n", $company_name,
  352.         $mailct - ($decct + $sitct),
  353.         $totbytes - ($decbytes + $sitbytes);
  354.         print "---------------  ------  ---------\n";
  355.         printf "total            %6d%11d\n", $mailct, $totbytes;
  356.     }
  357.     if ($calc_from) {
  358.         print "\n";
  359.         print "from                   count      bytes\n";
  360.         print "--------------------  ------  ---------\n";
  361.         for ($j = 0; $j < $site_total; $j++) {
  362.         next if ($site_noprint[$j]);
  363.         printf "%20s%8d%11d\n", $site_code[$j],
  364.             $site_ct[$j], $site_bytes[$j];
  365.         }
  366.         print "--------------------  ------  ---------\n";
  367.     }
  368.     if ($calc_user) {
  369.         #
  370.         # sort user data
  371.         #
  372.         for ($i = 0; $i < $luserct; $i++) {
  373.         $lstat[$i] = "$lusers[$i]\t$i";
  374.         }
  375.         @lsnew = sort cmp_lstat @lstat;
  376.         print "\n";
  377.         print "                   sent              received        \n";
  378.         print "local user         mails      bytes  mails      bytes\n";
  379.         print "-----------------  -----  ---------  -----  ---------\n";
  380.         for ($j = 0; $j < $luserct; $j++) {
  381.         ($lu, $i) = split(/\t/, $lsnew[$j]);
  382.         printf "%17s%7d%11d%7d%11d\n", $lusers[$i],
  383.             $lumct[$i], $lumbytes[$i],
  384.             $tumct[$i], $tumbytes[$i];
  385.         }
  386.         print "-----------------  -----  ---------  -----  ---------\n";
  387.         printf "%24d%11d%7d%11d\n",
  388.         $locct, $locbytes, $tocct, $tocbytes;
  389.     }
  390.     print "\n";
  391.  
  392.     exit(0);
  393.  
  394. #
  395. #    subroutines
  396. #
  397.  
  398. #
  399. # find the index into the local user data arrays
  400. #
  401. sub find_luser
  402. {
  403.     local($f) = $_[0];
  404.     local($i);
  405.  
  406.     for ($i = 0; $i < $luserct; $i++) {
  407.         return ($i) if ($lusers[$i] eq $f);
  408.     }
  409.     return(-1);
  410. }
  411.  
  412. #
  413. # find the index into the data arrays for the specified mail id
  414. #
  415. # search from the back because the probability is greater that the id
  416. # will be found closer toward the back
  417. #
  418. sub find_mail
  419. {
  420.     local($id) = $_[0];
  421.     local($i);
  422.  
  423.     for ($i = $mailct - 1; $i >= 0; $i--) {
  424.         return($i) if ($mails[$i] eq $id);
  425.     }
  426.     return(-1);
  427. }
  428.  
  429. #
  430. # get the mail id
  431. #
  432. sub get_id
  433. {
  434.     local($id) = $_[0];
  435.  
  436.     $id =~ s/.*sendmail: //i;
  437.     $id =~ s/:.*//;
  438.     return($id);
  439. }
  440.  
  441. #
  442. # get the size
  443. #
  444. sub get_size
  445. {
  446.     local($s) = $_[0];
  447.  
  448.     $s =~ s/.*size=//i;
  449.     $s =~ s/,.*//;
  450.     return($s);
  451. }
  452.  
  453. #
  454. # get the to addresses
  455. #
  456. sub get_to
  457. {
  458.     local($l) = $_[0];
  459.     local(@a, $t, $tl, $tu, $th);
  460.  
  461.     $l =~ s/.*to=//i;
  462.     $l =~ s/, delay=.*//i;
  463.     $l =~ s/\(.*\)//g;    # "real name" in parenthesis
  464.     $l =~ s/\<//g;
  465.     $l =~ s/\>//g;
  466.     $l =~ y/A-Z/a-z/;
  467.     $tl ="";
  468.     @a = split(/,/, $l);
  469.     foreach $t (@a) {
  470.         if ($t =~ m/::/) {
  471.             $t = do decnet2ip($t);
  472.         }
  473.         #
  474.         # the following are not real to addresses
  475.         #
  476.         elsif (($t =~ m/\|/) ||
  477.                ($t =~ m/\(cont\)/) ||
  478.                ($t =~ m/\[cont\]/) ||
  479.                ($t =~ m/\[\&c\]/)) {
  480.             next;
  481.         }
  482.         $t = do address_canon($t);
  483.         if ($tl) {
  484.             $tl .= "\t$t";
  485.         }
  486.         else {
  487.             $tl = "$t";
  488.         }
  489.     }
  490.     return($tl);
  491. }
  492.  
  493. #
  494. # make the address canonical
  495. #
  496. sub address_canon
  497. {
  498.     local($a) = $_[0];
  499.     local($tu, $th);
  500.  
  501.     if ($a =~ m/\%.*\@/) {
  502.         $tu = $a;
  503.         $tu =~ s/\%.*//;
  504.         $th = $a;
  505.         $th =~ s/.*\%(.*)\@.*/$1/;
  506.         $a = "$tu@$th";
  507.     }
  508.     if ($a =~ m/\@.*\@/) {
  509.         $tu = $a;
  510.         $tu =~ s/\@.*//;
  511.         $th = $a;
  512.         $th =~ s/.*\@(.*)\@.*/$1/;
  513.         $a = "$tu@th";
  514.     }
  515.     if ($a =~ m/:/) {
  516.         $tu = $a;
  517.         $tu =~ s/.*://;
  518.         $th = $a;
  519.         $th =~ s/:.*//;
  520.         $a = "$tu@$th";
  521.     }
  522.     if ($a =~ m/\.dnet/) {
  523.         $a =~ s/dnet/enet.dec.com/;
  524.     }
  525.     if ($a =~ m/^\\/) {
  526.         $a =~ s/^\\//;
  527.     }
  528.     return($a);
  529. }
  530.  
  531. #
  532. # get the from address
  533. #
  534. sub get_from
  535. {
  536.     local($f) = $_[0];
  537.     local(@x);
  538.  
  539.     $f =~ s/.*from=//;
  540.     $f =~ s/, size=.*//;
  541.     if ($f =~ m/\<.*\>/) {
  542.         $f =~ s/.*\<(.*)\>/$1/;
  543.     }
  544.     $f =~ s/\<//;
  545.     $f =~ s/\>//;
  546.     $f =~ y/A-Z/a-z/;
  547.     if ($f =~ m/::/) {
  548.         $f = do decnet2ip($f);
  549.     }
  550.     #
  551.     # get rid of the "real name" in parenthesis
  552.     #
  553.     if ($f =~ m/\(.*\)/) {
  554.         @ff = split(/ /, $f);
  555.         $f = $ff[0];
  556.     }
  557.     $f = do address_canon($f);
  558.     return($f);
  559. }
  560.  
  561. #
  562. # recursively turn the DECnet style mail address into a normal address
  563. #
  564. sub decnet2ip
  565. {
  566.     local($f) = $_[0];
  567.     local($u, $h);
  568.  
  569.     $u = $f;
  570.     $u =~ s/[a-z0-9_\.]+:://;
  571.     $h = $f;
  572.     $h =~ s/([a-z0-9_\.]+)::.*/$1/;
  573.     if ($u =~ m/::/) {
  574.         $f = do decnet2ip($u);
  575.     }
  576.     elsif ($u =~ m/\@/) {
  577.         $f = $u;
  578.         $f =~ s/\"//g;
  579.     }
  580.     else {
  581.         $f = "$u@$h.enet.dec.com";
  582.     }
  583.     return($f);
  584. }
  585.  
  586. #
  587. # compare the two local users
  588. # return -1 if $a should come before $b [used by sort]
  589. #
  590. sub cmp_lstat
  591. {
  592.     local(@da, @db);
  593.  
  594.     @da = split(/\t/, $a);
  595.     @db = split(/\t/, $b);
  596.     return -1 if ($lumct[$da[1]] > $lumct[$db[1]]);        # sent
  597.     return  1 if ($lumct[$da[1]] < $lumct[$db[1]]);
  598.     return -1 if ($tumct[$da[1]] > $tumct[$db[1]]);        # received
  599.     return  1 if ($tumct[$da[1]] < $tumct[$db[1]]);
  600.     return -1 if ($lumbytes[$da[1]] > $lumbytes[$db[1]]);
  601.     return  1 if ($lumbytes[$da[1]] < $lumbytes[$db[1]]);
  602.     return -1 if ($tumbytes[$da[1]] > $tumbytes[$db[1]]);
  603.     return  1 if ($tumbytes[$da[1]] < $tumbytes[$db[1]]);
  604.     return -1 if ($da[0] gt $db[0]);
  605.     return 1;
  606. }
  607.  
  608. --
  609. Hitoshi Doi, International Open Systems Engineering        doi@jrd.dec.com
  610. Japan Research and Development Center               decwrl!jrd.dec.com!doi
  611. Digital Equipment Corporation Japan      [from JUNET: doi@jrd.dec-j.co.jp]
  612.