#!/usr/bin/perl

package OC;
use Exporter;

@ISA = qw(Exporter);

@EXPORT = qw(Login);

BEGIN {

}

use strict;
use MIME::Types qw(by_suffix by_mediatype);
use CGI qw/:standard/;
use CGI::Carp qw(fatalsToBrowser);
use HTML::Template;
use DBI;
use Digest::MD5 qw(md5_hex);
use Tie::IxHash;
use Mail::Sender;

use vars qw /
%CONFIG
$_FILE
$_FOLDER
$_ERROR
$log
/;



sub ConnectToDatabase {
    if (!defined $::db) {
      $::db = DBI->connect("DBI:mysql:$CONFIG{db_name}:$CONFIG{db_host}:
        $CONFIG{db_port}",$CONFIG{db_username},$CONFIG{db_password})
	|| die "Can't connect to database server.";
    }
    return $::db;
}

sub PrepareSQL {
    my ($str) = (@_);
    $::sth=$::db->prepare($str);
}
 
sub ExecuteSQL {
    $::sth->execute(@_) || die "Could not execute SQL statement";
}

sub SendSQL {
    PrepareSQL(@_);
    ExecuteSQL();
}
 
sub FetchSQLData {
    return $::sth->fetchrow_array();
}

sub File_Type {
    my $mode=(stat($_[0]))[2];   
    return undef unless ($mode);
    if (substr(sprintf("%04o", $mode),0,1) ne '1') {
	return $_FOLDER;
    } else {
        return $_FILE;
    }
}

sub File_Time {
    return (stat($_[0]))[9];   
}




sub Login {
    my ($username,$password)=@_;
    SendSQL("select type,disabled,password from account where username='$username'");
    my ($type,$disabled,$db_pass)=FetchSQLData();
    return undef if ($disabled);
    my $crypted_pass='';
    if ($type ne 'article') {
        open(FILE,$CONFIG{password_file});
        while(my $line=<FILE>) {
            (my $un,$crypted_pass)=split(/:/,$line);
            if ($un eq $username) {
                last;
            }
        }
        close(FILE);
    } else {
       $crypted_pass=$db_pass;
    }

    if (($crypted_pass eq $password || $crypted_pass eq crypt($password,substr($crypted_pass,0,2))) && $username ne '') {
        return ($crypted_pass,$type);
    } else {
        return undef;
    }
}

sub Time_To_Str { 
    my $time=time;
    if ($_[0] ne '') {
        $time=$_[0];
    }
    my ($sec,$min,$hour,$mday,$mon,$year)=localtime($time);
    $year+=1900;
    $mon++;
     if ($_[1] eq '') {
        foreach ($sec,$min,$hour,$mday,$mon) {
            $_='0'.$_ if (length($_)<2);
        }
    }
    if ($_[1]=~m/date_only/) {
        return "$mday $mon $year";
    } elsif ($_[1] eq 'nice') {
        return "$mday/$mon/$year";
    } else {
        $year=substr($year,2,2);
        return "$year-$mon-$mday $hour:$min:$sec";
    }
    
}    

sub Url {
    my ($url)=$_[0];
    foreach (keys %{$CONFIG{alias}}) {
        $url=~s/^$_/$CONFIG{alias}{$_}/;
        $url=~s/ /\%20/g;
    }
    return $url;
}

sub Html_Table {
    my @table=@{$_[0]};
    my $result="<table border=0 cellpadding=0 cellspacing=0 bgcolor='$CONFIG{color}{bg0}' width=100%><tr><td>";
    $result.='<table border=0 cellpadding=3 cellspacing=1 width=100%>';
    my $first=1;
    foreach my $row (@table) {
        if ($first==1) {
            $result.="<tr bgcolor='$CONFIG{color}{table1}'>";
        } elsif (($first%2)==0) {
            $result.="<tr bgcolor='$CONFIG{color}{table2}'>";
        } else {
            $result.="<tr bgcolor='$CONFIG{color}{table3}'>";
        }
        foreach my $cell (@{$row}) {
            if ($first==1) {
                $result.="<td valign=top><b>$cell</b></td>";
            } else {
                $result.="<td valign=top>$cell</td>";
            }
        }
        $result.='</tr>';
        $first--;
    }
    $result.="</table></td></tr></table>";
}

sub Change_Password {
    my ($username,$password)=@_;
    my $crypted_pass=crypt($password,substr($username,0,2));

    SendSQL("select type from account where username='$username'");
    my $type=FetchSQLData();
    if ($type eq 'project') {
        my $new_file='';
        open(FIN,$CONFIG{password_file});
        while(my $line=<FIN>) {
            my ($un,$pw,@junk)=split(/:/,$line);
            if ($un eq $username) {
                $pw=$crypted_pass;
            }
            $new_file.=join(':',($un,$pw,@junk));
        }
        close(FIN);
        open(FOUT,">$CONFIG{password_file}");
        print FOUT $new_file;
        close(FOUT);
    }
    SendSQL("update account set password='$crypted_pass' where username='$username'");

    return $crypted_pass;
}

sub Store_Email {
    my $email=lc($_[0]);
    SendSQL("select hash from email_hash where email='$email'");
    my @result=FetchSQLData;
    if ($result[0]) {
        return $result[0];
    } else {
        my $counter=0;
        my $found=1;
        my $md5;
        while ($found) {
            $md5=md5_hex(time+$counter);
            SendSQL("select hash from email_hash where hash='$md5'");
            if (scalar(FetchSQLData)) {
                $found=1;
                $counter++;
            } else {
                $found=0;
            }
        }
        SendSQL("insert into email_hash (email,hash) values('$email','$md5')");
        return $md5;
    }
}

sub Filter_Emails {
    my ($src,$links,$lname,$year,$month,$msg_id,$cmd)=@_;
    my $list='0-9A-Z_-';
    my @line=split(/\n/,${$src});
    foreach my $source (@line) {
        $source=~s/<a[^>]*href="?mailto:[^"^>]*"?>([^<]*)<\/a>/$1/ig;
        $source=~s/<a[^>]*href="[^"^>]*post\.cgi[^"^>]*"?>([^<]*)<\/a>/$1/ig;
        while ($source=~m/([\.$list]+\@[\.$list]+\.[$list]+)/i) {
            my $email=$1;
            my $hidden=$email;
            my $md5=OC::Store_Email($email);
            $hidden=~s/^(.*\@.).*$/$1/g;
            $hidden.='... ';
            if ($links) {
                $hidden="<a href=\"$CONFIG{forum_url}/$lname/$year/$month/$msg_id/post?to=$md5\">$hidden</a>";
            }
            $source=~s/$email/$hidden/g;
        }
    }
    my $result=join("\n",@line);
    return (\$result);
}

sub Is_Html {
    my $text=${$_[0]};
    if ($text=~m/<table |<p |<br |<hr /i) {
        return 1;
    }
    return 0;
}

sub Smart_Reformat {
    my $text=${$_[0]};
    unless (Is_Html(\$text)) {
        $text=~s/\t/        /g;
        my @line=split(/\n/,$text);
        my $offset=0;
        my $prev_offset=0;
        my %history=();
        my $count=0;
        my $prev_item=0;
        foreach my $line (@line) {
            if ($line=~m/<!--.*include *file=\"(.*)\".*-->/) {
                my $file=$CONFIG{www_folder}.$1;
                my $fc=`cat $file`;
                if ($file=~m/\.\./) {
                    $fc='INCLUDE: Error in filename!';
                }
                $line=~s/<!--.*include *file=\".*\".*-->/$fc/;
            }
            if ($line=~m/^( *-[^-]{1})/) {
                my $prefix=$1;
                $line=~s/$prefix//; 
                $offset=length($prefix);
                $line="<li>$line</li>";
                if ($offset>$prev_offset) {
                    $history{$offset}=$count;
                    $line="<ul>".$line;
                    $count++;
                } elsif ($offset<$prev_offset && $count>1) {
                    $count--;
                    $line="$line";
                    my $diff=1;
                    foreach (sort keys %history) {
                        if ($_<=$offset) {
                            $diff=abs($count-$history{$_});
                        }
                    }
                    foreach (1..$diff) {
                        $line="</ul>".$line;
                    }
                }
                $prev_offset=$offset;
                $prev_item=1;
            } else {
                if ($prev_item) {
                    foreach (1..$count) {
                        $line="</ul>$line";
                    }
                }
                $count=0;
                $prev_offset=0;
                $prev_item=0;
            }
        }
        $text='';
        foreach my $line (@line) {
            unless ($line=~m/<\/?ul>|<\/?li>/) {
                $line.="\n";
            }
            $text.=$line;
        }
        if ($prev_item) {
            $text.="</ul>";
        }
        $text=~s/\n\n/<p>/g;
        $text=~s/\n/<br>/g;
    }
    return \$text;
}

sub List {
    my @files=();
    my @folders=();
    foreach (split(/ \//,join(' ',<$_[0]>))) {
        $_='/'.$_ unless($_=~m/^\//);
        my $ft=File_Type($_);
        if ($ft eq $_FOLDER) {
            push(@folders,$_.'/');
        } elsif ($ft eq $_FILE) {
            push(@files,$_);
        }
    }
#    @folders=Exclude(@folders);
#    @files=Exclude(@files);
    return(\@folders,\@files);
}


sub Get_Mailing_Lists {
    my @list;
    my @EXCLUDE=@{$CONFIG{excluded_mailinglists}};
    my ($folders,$files)=List("$CONFIG{month_folder}/*processed");
    foreach my $lname (@{$folders}) {
        $lname=~s/^.*\/([^\/]*)\.processed\/?$/$1/;
        my $found=0;
        foreach (@EXCLUDE) {
            if ($lname eq $_)  {
                $found++;
            }
        }
        push(@list,$lname) unless ($found);
    }
    return @list;
}

sub Small_Table {
    my ($title,$body,$param)=@_;
    my $width='';
    if ($param eq 'fit') {
        $width=' width=100% ';
    }
    my $result="<table bgcolor='$CONFIG{color}{bg0}' cellspacing=0 cellpadding=1 border=0 $width><tr><td>
      <table width=100% border=0 cellspacing=0 cellpadding=3>";
    if ($title ne '') {
        $result.="<tr><td bgcolor='$CONFIG{color}{bg3}'><b>$title</b></td></tr>";
    }
    $result.="<tr><td bgcolor='$CONFIG{color}{bg1}'><spacer type=block height=1 width=1></td></tr>
        <tr><td bgcolor='$CONFIG{color}{bg1}'>$body</td></tr>
        <tr><td bgcolor='$CONFIG{color}{bg1}'><spacer type=block height=1 width=1></td></tr>";
    $result.="</table></td></tr></table>";
    return $result;
}

sub To_Url {
    my ($file)=@_;
    $file=~s!/home/oc/www/!/!;
    if ($file=~m!^[^/]!) {
#        $file=~s!cvs/!/!;
        $file="$CONFIG{cvsget_url}/$file";
    }
    $file=~s/ /%20/s;
    return $file;
}

sub Li {
    return "<table border=0 cellspacing=0 cellpadding=0><tr><td valign=top><li>&nbsp;</li></td><td valign=top>$_[0]</td></tr></table>";
}

sub Title {
    return "<b><font size=+2 color=#bf0000>$_[0]</font></b><p>";
}

sub Truncate {
    my $result=$_[0];
    if (length($result)>$_[1]) {
        $result=substr($result,0,$_[1]-4).'...';
    }
    return $result;
}

sub Send_Mail {
    my %mail=%{$_[0]};
    my $sender=new Mail::Sender{
        smtp=>$CONFIG{mail_sender_smtp},
	from=>$mail{from},
	cc=>$mail{cc},
	to=>$mail{to},
	subject=>$mail{subject},
    };
    $sender->MailMsg({msg=>$mail{body}});
}

sub Mail_Webmaster {
    my $sender=new Mail::Sender{
        smtp=>$CONFIG{mail_sender_smtp},
	from=>'webmaster@opencores.org',
	to=>'mlampret@opencores.org',
	subject=>'OC web: auto message',
    };
    $sender->MailMsg({msg=>$_[0]});
}

sub Cat_File {
    my ($file)=@_;
    my $filename;
    if ($filename eq '') {
        $filename=$file;
        $filename=~s!^.*/([^/]+)$!$1!;
    }
    my ($mime_type, $encoding) = by_suffix($file);
    $mime_type="text/plain" if ($mime_type eq '');
    if (open(FILE,"$file")) {
        print "Content-type: $mime_type\nContent-Disposition: inline; filename=$filename\n\n";
        my $buffer='';
        while (read(FILE, $buffer, 16*1024)) {
            print $buffer;
        }
        close(FILE);
        my $time=OC::Time_To_Str(time);
        my $ip=$ENV{REMOTE_ADDR};
        `echo $time\t$ip\t$file >> /tmp/cvsget`;
    } else {
        return "Cannot open file: $file";
    }
}

sub Average {
    my (@points)=@_; 
    my $count=0;
    my $sum=0;
    my $result='';
    for(my $i=0;$i<scalar(@points);$i++) {
        $count+=$points[$i];
 	$sum+=($i+1)*$points[$i];
    }
    $count++ if ($count==0);
    return sprintf("%.1f",$sum/$count);
}

sub Target {
    my $in=$_[0];
    $in=~s/^(.*)\/$/$1/;
    my $file=readlink($in);
    if ($file ne '') {
        my $path=$in;
        $path=~s/^(.*\/)[^\/]*$/$1/;
	if (OC::File_Type($file)==$OC::_ERROR) {
            $file=$path.$file;
        }
        return Target($file);
    } else {
        return $_[0];
    } 
}

sub Finalize_Path {
    my $path=$_[0];
    $path=~s!//!/!g;			# remove //
    $path=~s!/\./!/!g;			# remove /./
    $path=~s!/[^/]+/\.\./!/!g;		# remove /folder/../
    if ($path=~m!/[^/]+/\.\./|/\./|//!) {
        Finalize_Path($path);
    } else {
        return $path;
    }
}

sub Log {
    my ($message)=@_;
    my ($package0, $fname0, $line0, $subroutine0,
      $hasargs0, $wantarray0, $evaltext0, $is_require0)=caller(0);
    my ($package1, $fname1, $line1, $subroutine1,
	$hasargs1, $wantarray1, $evaltext1, $is_require1)=caller(1);

    $fname1=substr($fname1,rindex($fname1,'/')+1);
    $subroutine1=substr($subroutine1,rindex($subroutine1,'::')+2);

    open(LOG,">>$CONFIG{access_log_file}");
    print LOG Time_To_Str(time)." $ENV{REMOTE_ADDR} - $fname1 - $subroutine1 - $message\n";
    close(LOG);
}

sub Error_Log {
    my ($message)=@_;
    my ($package0, $fname0, $line0, $subroutine0,
      $hasargs0, $wantarray0, $evaltext0, $is_require0)=caller(0);
    my ($package1, $fname1, $line1, $subroutine1,
	$hasargs1, $wantarray1, $evaltext1, $is_require1)=caller(1);

    $fname1=substr($fname1,rindex($fname1,'/')+1);
    $subroutine1=substr($subroutine1,rindex($subroutine1,'::')+2);

    open(LOG,">>$CONFIG{error_log_file}");
    print LOG Time_To_Str(time)." $ENV{REMOTE_ADDR} - $fname1 - $subroutine1 - $message\n";
    close(LOG);
}

sub Initialize {

    # country-codes http://www1.ics.uci.edu/pub/websoft/wwwstat/country-codes.txt

    $_FILE=1;
    $_FOLDER=2;
    $_ERROR=-1;

    %CONFIG=();

    $CONFIG{db_host}="localhost";
    $CONFIG{db_name}="opencores";
    $CONFIG{db_username}="oc";
    $CONFIG{db_password}="";
    $CONFIG{db_port}="3306";

    $CONFIG{mail_sender_smtp}='localhost';
    $CONFIG{add_account_from}='webmaster@opencores.org';
    $CONFIG{add_account_cc}='webmaster@opencores.org';
    $CONFIG{add_account_subject}='Your account';
  
    $CONFIG{account_home_folder}='/home/oc/www/people/';

    $CONFIG{lost_password_subject}='Your new password';
    $CONFIG{lost_password_file}='/home/oc/editor/lost.txt';

    $CONFIG{greet_file}='/home/oc/editor/greet.txt';
    $CONFIG{article_greet_file}='/home/oc/editor/article_greet.txt';

    $CONFIG{tmpl_project_file}='/home/oc/www/tmpl/dinamic.tmpl';
    $CONFIG{tmpl_project_list_file}='/home/oc/www/tmpl/dinamic.tmpl';
    $CONFIG{tmpl_account_file}='/home/oc/www/tmpl/dinamic.tmpl';
    $CONFIG{tmpl_cvsget_file}='/home/oc/www/tmpl/dinamic.tmpl';
    $CONFIG{tmpl_cvslinks_file}='/home/oc/www/tmpl/cvslinks.tmpl';

    $CONFIG{edit_image}="/images/edit.gif";

    $CONFIG{cvsroot}="/home/oc/cvs/";

    $CONFIG{cvsget_cache_folder}="/home/oc/www/tmp/cvsget_cache";

    $CONFIG{cvsweb_url}='/cvsweb.shtml';
    
    $CONFIG{project_url}="/projects";
    $CONFIG{account_url}="/people";
    $CONFIG{news_url}="/news";
    $CONFIG{article_url}="/articles";
    $CONFIG{post_url}="/forums/post";
    $CONFIG{forum_url}="/forums";
    $CONFIG{cvsget_url}="/cgi-bin/cvsget.cgi";

    $CONFIG{www_folder}='/home/oc/www/';

    $CONFIG{alias}{'/home/oc/www/'}='/';

    $CONFIG{cores_folder}="/home/oc/www/cores";

    $CONFIG{password_file}='/home/oc/cvs/CVSROOT/passwd';
    $CONFIG{cvs_passwd_junk}='cvs';
    
    $CONFIG{account_config_file}='/home/oc/editor/accounts.conf';

    $CONFIG{color}{bg0}="#000000";
    $CONFIG{color}{bg1}="#ffffff";
    $CONFIG{color}{bg2}="#f0f0f0";
#    $CONFIG{color}{bg3}="#bbccff";
    $CONFIG{color}{bg3}="#c0e0ff";
#    $CONFIG{color}{table1}="#bbccdd";
    $CONFIG{color}{table1}="#c0e0ff";
    $CONFIG{color}{table2}="#ffffff";
    $CONFIG{color}{table3}="#f0f0f0";

    # Mailing lists part

    $CONFIG{default_mailinglist}='cores';
    $CONFIG{month_folder}='/home/oc/www/ml-archive'; 
    my @excluded=('webmasters');
    $CONFIG{excluded_mailinglists}=\@excluded;

    # Wishlist part

    $CONFIG{wishlist_url}='/cgi-bin/wishlist.cgi';
    $CONFIG{wishlist_list_url}='/wishlist/';
    $CONFIG{wishlist_folder}='/home/oc/www/wishlist';
    $CONFIG{tmpl_wishlist_list_file}='/home/oc/www/tmpl/wishlist_list.tmpl';
    $CONFIG{tmpl_wishlist_add_file}='/home/oc/www/tmpl/wishlist_add.tmpl';
    $CONFIG{tmpl_wishlist_edit_file}='/home/oc/www/tmpl/wishlist_edit.tmpl';
    $CONFIG{tmpl_wishlist_result_file}='/home/oc/www/tmpl/wishlist_result.tmpl';
    $CONFIG{shtml_wishlist_list_file}='/home/oc/www/tmpl/wishlist_list.shtml';
    $CONFIG{shtml_wishlist_add_file}='/home/oc/www/tmpl/wishlist_add.shtml';
    $CONFIG{shtml_wishlist_edit_file}='/home/oc/www/tmpl/wishlist_edit.shtml';
    $CONFIG{shtml_wishlist_result_file}='/home/oc/www/tmpl/wishlist_result.shtml';

    # log part

    $CONFIG{access_log_file}='/home/oc/logs/cgi-access.log';
    $CONFIG{error_log_file}='/home/oc/logs/cgi-error.log';
    $CONFIG{download_info_log_file}='/home/oc/logs/download-info.log';


    # db part

    ConnectToDatabase;
}


Initialize;

1;
