home *** CD-ROM | disk | FTP | other *** search
/ Chip 2001 December / Chip_2001-12_cd1.bin / sharewar / mysql / data1.cab / Development / examples / tests / mail_to_db.pl < prev    next >
Encoding:
Perl Script  |  2001-11-02  |  7.6 KB  |  298 lines

  1. #!/usr/bin/perl
  2. # Copyright Abandoned 1998 TCX DataKonsult AB & Monty Program KB & Detron HB
  3. # This file is public domain and comes with NO WARRANTY of any kind
  4. #
  5. # This program is brought to you by Janne-Petteri Koilo with the 
  6. # administration of Michael Widenius.
  7.  
  8. # This program takes your mails and puts them into your database. It ignores
  9. # messages with the same from, date and message text.
  10. # You can use mail-files that are compressed or gzipped and ends with
  11. # -.gz or -.Z.
  12.  
  13. use DBI;
  14. use Getopt::Long;
  15.  
  16. $VER = "1.5";
  17.  
  18. $opt_db = "test";
  19. $opt_table = "mails";
  20. $opt_max_mail_size = 65536;
  21. $opt_db_engine = "mysql";
  22. $opt_host = "localhost";
  23. $opt_user = $opt_password = "";
  24. $opt_help = $opt_version = 0;
  25.  
  26. GetOptions("help","version","user=s","password=s",
  27.        "db_engine=s","db=s","host=s","max_mail_size=s") || usage();
  28.  
  29. usage($VER) if ($opt_help || $opt_version || !$ARGV[0]);
  30.  
  31. %months= ('Jan' => 1, 'Feb' => 2, 'Mar' => 3, 'Apr' => 4, 'May' => 5,
  32.       'Jun' => 6, 'Jul' => 7, 'Aug' => 8, 'Sep' => 9, 'Oct' => 10,
  33.       'Nov' => 11, 'Des' => 12);
  34.  
  35. $count_no_from = $count_no_txt = $count_too_big = 0;
  36. $count_forwarded_msgs = $count_duplicates = $no_subject = 0;
  37. $inserted_mails = 0;
  38.  
  39. $dbh = DBI->connect("DBI:$opt_db_engine:$opt_db:$opt_host",$opt_user,
  40.             $opt_password,{ PrintError => 0}) || die $DBI::errstr;
  41.  
  42. create_table_if_needed($dbh);
  43.  
  44. foreach (@ARGV)
  45. {
  46.   if (/^(.*)\.(gz|Z)$/) #checks if the file is compressed or gzipped
  47.   {
  48.     open(FILE, "zcat $_ |");
  49.     process_mail_file($dbh,$1);
  50.   }
  51.   else
  52.   {
  53.     open(FILE,$_);
  54.     process_mail_file($dbh,$_);
  55.   }
  56. }
  57.  
  58. $ignored = $count_no_from + $count_no_txt + $count_too_big + $count_duplicates + $no_subject;
  59. print "Mails inserted:\t\t\t$inserted_mails\n";
  60. print "Mails ignored:\t\t\t$ignored\n";
  61. print "Mails without \"From:\" -field:\t$count_no_from\n";
  62. print "Mails without message:\t\t$count_no_txt\n";
  63. print "Too big mails (> $opt_max_mail_size):\t$count_too_big\n";
  64. print "Duplicate mails:\t\t$count_duplicates\n";
  65. print "Forwarded mails:\t\t$count_forwarded_msgs\n";
  66. print "Mails altogether:\t\t"; 
  67. print $inserted_mails+$ignored;
  68. print "\n";
  69. exit(0);
  70.  
  71. sub usage
  72. {  
  73.   my($VER)=@_;
  74.   
  75.   $0 =~ s/.\/(.+)/$1/;
  76.   if ($opt_version)
  77.   {
  78.     print "$0 version $VER\n";
  79.   } 
  80.   else
  81.   {
  82.     print <<EOF;
  83. $0 version $VER
  84.  
  85. Usage: $0 [options] file1 [file2 file3 ...]
  86.  
  87. Description: Inserts mails from file(s) into a database
  88.  
  89. Options:
  90. --help             show this help and exit
  91. --version          shows the version of the program
  92. --db_engine=...    database server (default: $opt_db_engine)
  93. --db=...           database to be used (default: $opt_db)
  94. --host=...         hostname to be used (default: $opt_host)
  95. --password=...     user password for the db server
  96. --user=...         username for the db server
  97. --max_mail_size=#  max size of a mail to be inserted into the db.
  98.                    mail will be ignored if it exceeds this size
  99.                    (default $opt_max_mail_size)
  100. EOF
  101.   }
  102.   exit(0);
  103. }
  104.  
  105. sub create_table_if_needed
  106. {
  107.   my ($dbh)=@_;
  108.   my ($sth,$create);
  109.   
  110.   $sth = $dbh->prepare("select count(*) from $opt_table") or die $dbh->errstr;
  111.   if (!$sth->execute)
  112.   {
  113.     $create = "CREATE TABLE $opt_table (msg_nro mediumint unsigned not null ";
  114.     $create .= "auto_increment, date DATETIME NOT NULL, time_zone CHAR(6) ";
  115.     $create .= "NOT NULL, mail_from char(120) not null, reply char(120), ";
  116.     $create .= "mail_to TEXT, cc TEXT, sbj char(200), txt MEDIUMTEXT NOT ";
  117.     $create .= "NULL, file char(32) noT NULL, hash INT NOT NULL, key ";
  118.     $create .= "(msg_nro), primary key (mail_from, date, time_zone, hash))";
  119.     $sth = $dbh->prepare($create) or die $dbh->errstr;
  120.     $sth->execute() or die $dbh->errstr;
  121.   }  
  122. }
  123.  
  124. sub process_mail_file
  125. {
  126.   my ($dbh,$file_name)= @_;
  127.   my (%values,$type,$check);
  128.  
  129.   %values=(); $type="";
  130.   $check=0;
  131.  
  132.   while (<FILE>)
  133.   {
  134.     chop;
  135.     if ($type ne "message")
  136.     { 
  137.       if (/^Reply-To: (.*)/i)  # finding different fields from file
  138.       {
  139.     $type="reply";
  140.     $values{$type}= $1;
  141.       }
  142.       elsif (/^From: (.*)/i)
  143.       {
  144.     $type="from";
  145.     $values{$type}= $1;
  146.       }
  147.       elsif (/^To: (.*)/i)
  148.       {
  149.     $type="to";
  150.     $values{$type}= $1;
  151.       }
  152.       elsif (/^Cc: (.*)/i)
  153.       {
  154.     $type="cc";
  155.     $values{$type}= $1;
  156.       }
  157.       elsif (/^Subject: (.*)/i)
  158.       {
  159.     $type="subject";
  160.     $values{$type}= $1;
  161.       }
  162.       elsif (/^Date: (.*)/i)
  163.       {
  164.     date_parser($1,\%values);
  165.     $type="rubbish";
  166.       }
  167.       elsif (/^[\w\W-]+:\s/)
  168.       {
  169.     $type="rubbish";  
  170.       }
  171.       elsif ($_ eq "")
  172.       { 
  173.     $type="message";
  174.     $values{$type}="";
  175.       }
  176.       else
  177.       {
  178.     s/^\s*/ /;
  179.     $values{$type}.= $_;
  180.       }
  181.     }
  182.     elsif ($check!=0 && $_ ne "") # in case of forwarded messages
  183.     {
  184.       $values{$type}.= "\n" . $_;
  185.       $check--;
  186.     }
  187.     elsif (/^From .* \d\d:\d\d:\d\d\s\d\d\d\d$/)
  188.     {
  189.       $values{'hash'}= checksum("$values{'message'}");
  190.       update_table($dbh,$file_name,\%values);
  191.       %values=(); $type="";
  192.       $check=0;
  193.     }
  194.     elsif (/-* forwarded message .*-*/i) # in case of forwarded messages
  195.     {
  196.       $values{$type}.= "\n" . $_;
  197.       $check++;
  198.       $count_forwarded_msgs++;
  199.     }
  200.     else
  201.     {
  202.       $values{$type}.= "\n" . $_;
  203.     }
  204.   }
  205.   $values{'hash'}= checksum("$values{'message'}");
  206.   update_table($dbh,$file_name,\%values);
  207. }
  208.  
  209. ########
  210.  
  211. # converts date to the right form
  212.  
  213. sub date_parser
  214. {
  215.   my ($date_raw,$values)=@_;
  216.  
  217.   $date_raw =~ /.*?(\d{1,2}?) (.+?) (\d{2,4}?) (\d\d:\d\d:\d\d?) ([\w-+]{3,5})/;
  218.   $values->{'date'}=$3 . "-" . $months{$2} . "-" . "$1 $4";
  219.   $values->{'time_zone'}=$5;
  220. }
  221.  
  222. #########
  223.  
  224. # this is runned when the whole mail is gathered.
  225. # this actually puts the mail to the database.
  226.  
  227. sub update_table
  228. {
  229.   my($dbh,$file_name,$values)=@_;
  230.   my($query);
  231.  
  232.   if (! defined($values->{'subject'}) || !defined($values->{'to'}) || !defined)
  233.   {
  234.     $no_subject++;
  235.     return;            # Ignore these
  236.   }
  237.   $values->{'message'} =~ s/^\s*//; #removes whitespaces from the beginning 
  238.   $values->{'message'} =~ s/\s*$//; #removes whitespaces from the end
  239.   $query = "insert into $opt_table values ('" . "NULL','" . $values->{'date'};
  240.   $query .= "','" . $values->{'time_zone'} . "',";
  241.   $query .= (defined($values->{'from'}) ? $dbh->quote($values->{'from'}) : "NULL") . ",";
  242.   $query .= (defined($values->{'reply'}) ? $dbh->quote($values->{'reply'}) : "NULL") . ",";
  243.  
  244.   $query .= (defined($values->{'to'}) ? $dbh->quote($values->{'to'}) : "NULL") . ","; 
  245.   $query .= (defined($values->{'cc'}) ? $dbh->quote($values->{'cc'}) : "NULL") . ","; 
  246.   $query .= $dbh->quote($values->{'subject'}) . ",";
  247.   $query .= $dbh->quote($values->{'message'}) . "," . $dbh->quote($file_name);
  248.   $query .= ",'" . $values->{'hash'} . "')";
  249.   
  250.   if (length($values->{'message'}) > $opt_max_mail_size) #disables big message
  251.   {
  252.     $count_too_big++;
  253.   }
  254.   elsif ($values->{'from'} eq "") #disables mails with no from field
  255.   {
  256.     $count_no_from++;
  257.   }
  258.   elsif ($values->{'message'} eq "") #disables mails with no message text
  259.   {
  260.     $count_no_msg_text++;
  261.   }
  262.   elsif ($dbh->do($query))
  263.   {
  264.     $inserted_mails++;
  265.   }
  266.   elsif (!($dbh->errstr =~ /^Duplicate entry /)) #disables duplicates
  267.   {
  268.       print "Aborting: Got error '$dbh->errstr' for query: '$query'\n";
  269.   }
  270.   else
  271.   {
  272.     $count_duplicates++;    
  273.   }
  274.   $query="";
  275. }
  276.  
  277.  
  278. ##########
  279.  
  280. # In case you have two identical messages we wanted to identify them
  281. # and remove additionals;  We do this by calculating a hash number of the
  282. # message and ignoring messages with the same from, date and hash.
  283. # This function calculates a simple 32 bit hash value for the message.
  284.  
  285. sub checksum
  286. {
  287.   my ($txt)= @_;
  288.   my ($crc,$i,$count);
  289.   $count = length($txt);
  290.   for ($crc = $i = 0; $i < $count ; $i++)
  291.   {
  292.     $crc = (($crc << 1) + (ord (substr ($txt, $i, 1)))) +
  293.       (($crc & (1 << 30)) ? 1 : 0);
  294.     $crc &= ((1 << 31) -1);
  295.   }
  296.   return $crc;
  297. }
  298.