# $Id: authors.pm,v 1.24 2004/11/12 05:44:57 gwolf Exp $
######################################
# Comas - Conference Management System
######################################
# Copyright 2003 CONSOL
# Congreso Nacional de Software Libre (http://www.consol.org.mx/)
#   Gunnar Wolf <gwolf@gwolf.cx>
#   Manuel Rabade <mig@mig-29.net>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
######################################

######################################
# Module: Comas::HTML::authors
# Manage registration of proposals.
######################################
# Depends on:
#
# Comas::File - Manages the proposals' files
# Comas::Proposal - Handles the interaction with a person for Comas
# Comas::Person - Handles the interaction with a person for Comas
# Comas::HTML::common - Common functions for the HTML FrontEnd
# Data::FormValidator - Validates user input based on input profile
# HTML::FromText - Marks up plain text as HTML
# Net::SMTP - Simple Mail Transfer Protocol Client

# This module is not meant to be called on its own, it should be called from
# Comas::HTML.

package Comas::HTML::authors;

use strict;
use warnings;
use Carp;

use Comas::File;
use Comas::Person;
use Comas::Proposal;
use Comas::HTML::common qw(:all);
use Comas::Conf qw(:read);

use Data::FormValidator;
use HTML::FromText;
use Date::Calc qw(Time_to_Date);
use Net::SMTP;

use Exporter;

our @ISA = qw(Exporter);
our @EXPORT_OK = qw(authors_data authors_data_delete proposals_new
                    proposals_list proposals_edit proposals_delete
                    proposals_authors proposals_file);
our %EXPORT_TAGS = (all => [@EXPORT_OK]);

=head1 NAME
    
Comas::HTML::authors - Front-End to manage authors and their proposals.

=head1 SYNOPSIS

This module is not meant to be used by itself, but as an auxiliary to
L<Comas::HTML|Comas::HTML>. Please check L<Comas::HTML|Comas::HTML>'s
documentation, in the B<Front End Tasks> section, for further details on the
usage for this functions.

=head1 INTERNALS

=head2 METHODS

=head3 $res = $html->authors_data;

Modify author's data (right now only the resume).

=cut

sub authors_data {
    my ($input_profile, $template, $validator, $val_results, $person);
    my $h = shift;
    
    $template = $h->new_template('attendees/authors/data.tmpl');
    
    if (defined($h->{-params}->{validate})) {
        $person = Comas::Person->new(-db => $h->{-db},
                                     -id => $h->{-session}->{-person});
        $person->set_resume($h->{-params}->{-resume});
        return $h->attendees_menu('AUTHOR_DATA_CHANGED');
    } else {
        $person = Comas::Person->new(-db => $h->{-db},
                                     -id => $h->{-session}->{-person});
        $template->param(-resume => $person->get_resume);
        return $template->output;
    }
}

=pod

=head3 $res = $html->proposals_new;

Process a new proposal.

=cut

sub proposals_new {
    my ($input_profile, $template, $validator, $val_results, $proposal);
    my $h = shift;
    
    $input_profile = {required => [ qw(-title -abstract -track_id
                                       -prop_type_id) ],
                      filters => [ qw( trim ) ] };
    
    $template = $h->new_template('attendees/authors/proposals_new.tmpl');
    
    if (defined($h->{-params}->{validate})) {
        $validator = Data::FormValidator->new;
        $val_results = $validator->check ( $h->{-params}, $input_profile);
        if ($val_results->has_missing) {
            $template->param(_validator2html($val_results));
        } else {
            $proposal = Comas::Proposal->new(-db=>$h->{-db},
                                             %{$val_results->valid});
            unless(defined $proposal) {
                if (Comas::Proposal->lastError == 203) {
                    return $h->attendees_menu('PROPOSAL_TOO_LATE');
                }
            } else {
                unless($proposal->add_author($h->{-session}->{-person})) {
                    if (Comas::Proposal->lastError == 302) {
                        $proposal->delete;
                        return $h->attendees_menu('TOO_MANY_PROPOSALS_FOR_YOU');
                    }
                } else {
		    my ($from, $tmpl);
		    $tmpl=$h->{-config}{-tmpl_path} . 'mail/proposal_new.txt';
		    if ($from = get_conf($h->{-db},'proposal_new_mail_from')
			and -f $tmpl) {
			_send_mail_new_proposal($proposal, $tmpl, $from);

		    }
                    return $h->attendees_menu('PROPOSAL_NEW');
                }
            }
        }
    }

    $template->param($h->{-params});
    $template->param(-track_list => 
                     _catalog2html_opts($h->{-db},"track",
                                        $h->{-params}->{-track_id}),
                     -prop_type_list =>
                     _catalog2html_opts($h->{-db},"prop_type",
                                        $h->{-params}->{-prop_type_id},
                                        'priv_prop_types'));
    return  $template->output;
}

=pod

=head3 $res = $html->proposals_new($message);

Lists the author proposals. Can receive an optional explanatory message that
will be passed to the template in case there was an error manipulating a
proposal (modification, creation, etc.)

=cut

sub proposals_list {
    my ($input_profile, $template, $validator, $val_results, $person,
        @proposals, $prop, %status);
    my $h = shift;
    my $message = shift;
    
    $input_profile = {required => [ qw(-resume) ], filters => [ qw( trim ) ] };
    
    $template = $h->new_template('attendees/authors/proposals_list.tmpl');
    
    $person = Comas::Person->new(-db => $h->{-db},
                                 -id => $h->{-session}->{-person});

    %status = $h->{-db}->getCatalog('prop_status');

    @proposals = $person->get_props;
    
    my ($prop_temp, @loop);
    foreach $prop (@proposals) {
        my %row;
        $prop_temp = Comas::Proposal->new(-db => $h->{-db},
                                          -id => $prop);
        $row{-id} = $prop_temp->{-id};
        $row{-title} = $prop_temp->get_title;
        $row{-prop_status} = $status{$prop_temp->get_prop_status_id};
        push (@loop, \%row);
    }    
    $template->param(PROPOSALS => \@loop);

    if (defined $message) {
        $template->param($message => 1);
    }

    return $template->output;    
}

=pod

=head3 $res = $html->proposals_edit;

Edit a given proposal of the current author.

=cut

sub proposals_edit {
    my ($input_profile, $template, $validator, $val_results, $proposal,
        %authors, %prop_data);
    my $h = shift;
    
    $input_profile = {required => [ qw(-title -abstract -track_id
                                       -prop_type_id) ],
                      filters => [ qw( trim ) ] };
    
    # Let's chech if the proposal belong to the author.
    $proposal = Comas::Proposal->new(-db => $h->{-db},
                                     -id => $h->{-path}[4]);
    %authors = $proposal->get_authors(-result=>'hash');
    unless ($authors{$h->{-session}->{-person}}) {
        return $h->attendees_menu;
    }

    # Initial template stuff
    $template = $h->new_template('attendees/authors/proposals_edit.tmpl');
    
    %prop_data = $proposal->get_data;
    
    $template->param(-id => $prop_data{-id});
    $template->param(-prop_status => $h->{-db}->getCatDescr('prop_status',
                                               $prop_data{-prop_status_id}));
    $template->param(-comments => text2html($prop_data{-comments}, 
                                            lines => 1));
    
    # Cool, the form have been posted 
    if (defined($h->{-params}->{validate})) {
        $validator = Data::FormValidator->new;
        $val_results = $validator->check ( $h->{-params}, $input_profile);
        # Whops, something is bad 
        if ($val_results->has_missing) {
            $template->param($h->{-params});
            $template->param(-track_list => 
                             _catalog2html_opts($h->{-db},"track",
                                                $h->{-params}->{-track_id}),
                             -prop_type_list =>
                             _catalog2html_opts($h->{-db},"prop_type",
                                                $h->{-params}->{-prop_type_id},
                                                'priv_prop_types'));
            $template->param(_validator2html($val_results));
            return $template->output;
        } else {
            # Everything is fine, lets update the proposal
            unless($proposal->set_data(%{$val_results->valid})) {
                if (Comas::Proposal->lastError == 206) {
                    return $h->proposals_list('CANT_MODIFY_ACCEPTED_PROPOSAL');
                }
            } else {
                # Let's send the mail to the academic committee
                _send_proposal_modif_mail($proposal,
                                          $h->{-config}->{-tmpl_path} .
                                           'mail/proposal_modif.txt',
                                          %prop_data);
                # And return the proposals lists
                return $h->proposals_list('PROPOSAL_DATA_CHANGED');
            }
        }
    } else {
        $template->param(-title => $proposal->get_title);
        $template->param(-abstract => $proposal->get_abstract);
        $template->param(-track_list => 
                         _catalog2html_opts($h->{-db},"track",
                                            $proposal->get_track_id),
                         -prop_type_list =>
                         _catalog2html_opts($h->{-db},"prop_type",
                                            $proposal->get_prop_type_id,
                                            'priv_prop_types'));
        return $template->output;
    }
}

=pod

=head3 $res = $html->proposals_edit;

Delete a proposal.

=cut

sub proposals_delete {
    my $h = shift;
    my ($proposal, %authors, $template);

    # Let's check if the proposal belongs to this author.
    $proposal = Comas::Proposal->new(-db => $h->{-db},
                                     -id => $h->{-path}[4]);

    %authors = $proposal->get_authors(-result=>'hash');

    unless ($authors{$h->{-session}->{-person}}) {
        return $h->attendees_menu;
    }

    if (defined($h->{-params}->{validate})) {
	# $proposal->delete will take care of deleting any files regarding the
	# proposal as well
        unless ($proposal->delete) {
            if (Comas::Proposal->lastError == 207) {
                return $h->proposals_list('CANT_DELETE_ACCEPTED_PROPOSAL');
            } else {
		return $h->proposals_list('CANT_DELETE_PROPOSAL');
	    }
        }
        return $h->proposals_list('PROPOSAL_DELETED');
    } else {
        $template = $h->new_template('attendees/authors/proposals_delete.tmpl');
        $template->param(-id => $proposal->{-id});
        $template->param(-title => $proposal->get_title);
        return $template->output;
    }
}

=pod

=head3 $res = $html->proposals_authors;

Manages the proposal's authors. There are four actions:

=over 2

=item * Add
Add an author to the proposal.

=item * Delete
Delete an author of the proposal.

=item * Move
Change the mention order of the authors.

=item * List
List the authors of the proposal. This is the default action.

=back

=cut

sub proposals_authors {
    my $h = shift;
    my ($template, $proposal, %authors, $author);

    # Check if this proposal belongs to this author.
    $proposal = Comas::Proposal->new(-db => $h->{-db},
                                     -id => $h->{-path}[4]);
    %authors = $proposal->get_authors(-result=>'hash');
    unless ($authors{$h->{-session}->{-person}}) {
        return $h->attendees_menu;
    }

    $template = $h->new_template('attendees/authors/authors_edit.tmpl');

    $template->param(-id => $h->{-path}[4]);

    if (defined $h->{-path}[5]) {
        if ($h->{-path}[5] eq 'add') {
            my $login = $h->{-params}->{-login};
            $login =~ s/^\ +//;
            my @ids = Comas::Person->search(-db=>$h->{-db}, 
                                            -login => $login);
            if ($login =~ /^\s*$/) {
                $template->param(LOGIN_EMPTY => 1);
            } elsif (scalar @ids < 1) {
                $template->param(LOGIN_DONT_EXIST => 1);
            } elsif ($authors{$ids[0]}) {
                $template->param(AUTHOR_ALREDY_ADDED => 1);
            } else {
                unless($proposal->add_author($ids[0])) {
                    if (Comas::Proposal->lastError == 302) {
                        $template->param(TOO_MANY_PROPOSALS => 1);
                    } elsif (Comas::Proposal->lastError == 303) {
                        $template->param(TOO_MANY_AUTHORS => 1);
                    } elsif (Comas::Proposal->lastError == 305) {
                        $template->param(CANT_ADD_AUTHOR_PROPOSAL_ACCEPTED =>
                                         1);
                    }
                } else {
                    $template->param(AUTHOR_ADDED => 1);

		    # Send a mail to the newly added coauthor notifying him
		    # he has been added if so configured
		    my $mail_tmpl = $h->{-config}{-tmpl_path} . 
			'mail/added_as_author.txt';
		    if (my $from = get_conf($h->{-db},'proposal_new_mail_from')
			and -f $mail_tmpl) {
			my ($new, $this);
			$new=Comas::Person->new(-db=>$h->{-db}, -id=>$ids[0]);
			$this=Comas::Person->new(-db=>$h->{-db},
						 -id=>$h->{-session}{-person});

			_send_mail_added_as_author($proposal, $new, $this, 
						   $mail_tmpl, $from);
		    }
                }
            }            
        } elsif ($h->{-path}[5] eq 'move') {
            my $pos = $h->{-params}->{-pos};
            $pos =~ s/^\ +//;
            if ($pos < 0 || $pos > 99 || $pos =~ /\D/ || $pos =~ /^\s*$/) {
                $template->param(BAD_POSITION => 1);
            } else {
                $proposal->move_author($h->{-path}[6], $h->{-params}->{-pos});
                if (Comas::Proposal->lastError == 305) {
                    $template->param(CANT_MOVE_AUTHOR_PROPOSAL_ACCEPTED => 1);
                } else {
                    $template->param(AUTHOR_MOVED => 1);
                }
            }
        } elsif ($h->{-path}[5] eq 'delete') {
            $proposal->del_author($h->{-path}[6]);
            if (Comas::Proposal->lastError == 305) {
                $template->param(CANT_DELETE_AUTHOR_PROPOSAL_ACCEPTED => 1);
            } else {
                $template->param(AUTHOR_DELETED => 1);
                if ($h->{-path}[6] eq $h->{-session}->{-person}) {
                    return $h->proposals_list('DELETED_YOURSELF');
                }
            }
        }
    }


    %authors = $proposal->get_authors(-result=>'hash');
    my ($author_temp, @loop);
    foreach my $author_id (sort { $authors{$a} <=> $authors{$b} }
                           keys %authors) {
        my %row;
        $author_temp = Comas::Person->new(-db => $h->{-db},
                                          -id => $author_id);
        $row{-prop_id} = $proposal->{-id};
        $row{-author_id} = $author_temp->{-id};
        $row{-mention_order} = $authors{$author_id};
        $row{-firstname} = $author_temp->get_firstname;
        $row{-famname} = $author_temp->get_famname;
        $row{-email} = $author_temp->get_email;
        push (@loop, \%row);
    }
    $template->param(AUTHORS => \@loop);

    return $template->output;
}

=pod

=head3 $res = $html->proposals_file;

Manages the proposal's files. There are three actions:

=over 2

=item * Put
Upload a file.

=item * Delete
Delte the file.

=item * Get
Send the proposal's file to the browser. This is the default action.

=back

=cut

sub proposals_file {
    my $h = shift;
    my ($proposal, $template, %authors);
    
    # Let's check if the proposal belong to the author.
    $proposal = Comas::Proposal->new(-db => $h->{-db},
                                     -id => $h->{-path}[4]);
    
    %authors = $proposal->get_authors(-result=>'hash');
    unless ($authors{$h->{-session}->{-person}}) {
        return $h->attendees_menu;
    }
    
    $template = $h->new_template('attendees/authors/proposals_file.tmpl');

    $template->param(-id => $proposal->{-id});
    
    if (defined($h->{-path}[5]) && $h->{-path}[5] eq 'put') {
        foreach my $upload ($h->{-upload}) {
            if ($upload->size > 0) {
		my ($fh, $data, $id);
		$fh = $upload->fh;
		$data = join('', <$fh>);

		if ($id = $proposal->new_file(-filename => $upload->filename,
					      -descr => $h->{-params}{-descr},
					      -data => $data)) {
		    my $file = Comas::File->new(-db => $h->{-db}, -id => $id);
		    # File was successfully created - Send the confirmation 
		    # mail
                    _send_proposal_file_mail($file, $proposal, 
                                             $h->{-config}->{-tmpl_path} .
                                             'mail/proposal_file.txt');
                    $template->param(FILE_ADDED => 1);
		} else {
		    # File was not successfully received
                    if (Comas::Proposal->lastError == 206) {
                        $template->param(CANT_MODIFY_ACCEPTED_PROPOSAL => 1);
                    }
                }
            }
        }
    }
    
    if (defined $h->{-path}[5] and $h->{-path}[5] eq 'delete' and
	my $id = $h->{-path}[6]) {
	unless (grep {$id == $_} $proposal->get_file_ids) {
	    carp 'Tried to delete non-matching file - proposal '.
		$h->{path}[4] . ', file '.$id;
	    $template->param(CANT_DELETE_FILE=>1);
	}

	if ($proposal->delete_file($id)) {
	    $template->param(FILE_DELETED=>1);
	} else {
	    $template->param(CANT_DELETE_FILE=>1);
	}
    }

    if (my @files = $proposal->get_files) {
	my @data;
	for my $file (@files) {
	    push @data, {-ID => $file->get_id,
			 -FILENAME => $file->get_filename,
			 -DESCR => $file->get_descr,
			 -SIZE => $file->get_filesize};
	}
	$template->param(files => \@data);
    }
    
    return $template->output;
}

=pod

=head2 LOCAL FUNCTIONS

=head3 $res = _send_proposal_modif_mail($proposal, $mail_tmpl, %old_data);

Send a notification via email to the academic committee about the modifications
of a proposal, it should be used B<before> the object was modified (to be sure
that the proposal was modified).

The arguments are:

=over 2

=item - $proposal

L<Comas::Proposal|Comas::Proposal> object of the current proposal.

=item - $mail_tmpl

Filename of the email template with full path.

=item - %old_data

Hash with the proposal's data before it was modified (like the one in
L<Comas::Person|Comas::Person>.

=back

This function also needs the following configuration values: smtp_host (if isn't
defined 127.0.0.1 is used), proposal_modif_mail_to (reciver of notifications)
and proposal_modif_mail_from (sender of notifications).

The C<$res> retrun value is undef in case of an error or true if successful.

=cut

sub _send_proposal_modif_mail {
    my ($mail, %mail_subst, $smtp_host, $mail_to, $smtp, $mail_from);

    my $proposal = shift;
    my $mail_tmpl = shift;
    my %old_data = @_;
    my %new_data = $proposal->get_data;

    unless (-r $mail_tmpl and open(TMPL, '<', $mail_tmpl)) {
	warn "Could not open mail template ($mail_tmpl): $!\n";
	warn 'Mail will not be sent to the academic committee.';
	return undef;
    }
    while (<TMPL>) {
        $mail .= $_;
    }
    close(TMPL);

    $mail_subst{PROP_ID} = $old_data{-id};    

    $mail_subst{TITLE} = $old_data{-title};
    unless ($old_data{-title} eq $new_data{-title}) {
        $mail_subst{NEW_TITLE} =  $new_data{-title};
    } else {
        $mail_subst{NEW_TITLE} = 'No changes';
    }

    $mail_subst{ABSTRACT} = $old_data{-abstract};
    unless ($old_data{-abstract} eq $new_data{-abstract}) {
        $mail_subst{NEW_ABSTRACT} =  $new_data{-abstract};
    } else {
        $mail_subst{NEW_ABSTRACT} = 'No changes';
    }

    $mail_subst{PROP_TYPE} = $proposal->{-db}->getCatDescr('prop_type',
						   $old_data{-prop_type_id});
    
    unless ($old_data{-prop_type_id} eq $new_data{-prop_type_id}) {
        $mail_subst{NEW_PROP_TYPE} = $proposal->{-db}->getCatDescr('prop_type',
						    $new_data{-prop_type_id});
    } else {
        $mail_subst{NEW_PROP_TYPE} = 'No changes';
    }
    
    $mail_subst{TRACK} = $proposal->{-db}->getCatDescr('track',
						       $old_data{-track_id});
    unless ($old_data{-track_id} eq $new_data{-track_id}) {
        $mail_subst{NEW_TRACK} = $proposal->{-db}->getCatDescr('track',
							 $new_data{-track_id});
    } else {
        $mail_subst{NEW_TRACK} = 'No changes';
    }

    $smtp_host = get_conf($proposal->{-db}, 'smtp_host') || '127.0.0.1';
    
    unless($mail_to = get_conf($proposal->{-db}, 'proposal_modif_mail_to')) {
        warn "Couldn't get recipient address, please check your configuration.\n";
	warn "Mail will not be sent to the academic committee.\n";
	return undef;
    }

    unless($mail_from = get_conf($proposal->{-db}, 'proposal_modif_mail_from')) {
        warn "Couldn't get sender address, please check your configuration.\n";
	warn "Mail will not be sent to the academic committee.\n";
	return undef;
   }
    
    # Here goes my mail-processing mini-template-engine!
    for my $key (keys %mail_subst) {
        $mail =~ s/__${key}__/$mail_subst{$key}/gs;
    }
    
    unless ($smtp = Net::SMTP->new($smtp_host)) {
        warn "Couldn't contact SMTP server\n";
        warn "Mail will not be sent to the authors.\n";
        return undef;
    }

    $smtp->mail($mail_from);
    $smtp->to($mail_to);
    $smtp->data();
    $smtp->datasend($mail);
    $smtp->dataend();
    $smtp->quit();
    return 1;
}

=pod

=head3 $res = _send_proposal_file_mail($file, $proposal, $mail_tmpl);

Send a notification via email to the academic committee when a new file is
submitted.

The arguments are:

=over 2

=item - $file

L<Comas::File|Comas::File> object of the current file
=item - $proposal

L<Comas::Proposal|Comas::Proposal> object of the current proposal.

=item - $mail_tmpl

Filename of the email template with full path.

=back

This function also needs the following configuration values: smtp_host (if isn't
defined 127.0.0.1 is used), proposal_modif_mail_to (reciver of notifications)
and proposal_modif_mail_from (sender of notifications).

The C<$res> retrun value is undef in case of an error or true if successful.

=cut

sub _send_proposal_file_mail {
    my ($mail, %mail_subst, $smtp_host, $mail_to, $smtp, $mail_from);
    my ($file, $proposal, $mail_tmpl) = @_;
    my %prop_data = $proposal->get_data;
    unless (-r $mail_tmpl and open(TMPL, '<', $mail_tmpl)) {
	warn "Could not open mail template ($mail_tmpl): $!\n";
	warn 'Mail will not be sent to the academic committee.';
	return undef;
    }
    while (<TMPL>) {
        $mail .= $_;
    }
    close(TMPL);

    $mail_subst{PROP_ID} = $prop_data{-id};
    $mail_subst{TITLE} = $prop_data{-title};

    $mail_subst{FILENAME} = $file->get_filename;
    $mail_subst{SIZE} = $file->get_filesize;

    $smtp_host = get_conf($file->{-db}, 'smtp_host') || '127.0.0.1';

    unless($mail_to = get_conf($proposal->{-db}, 'proposal_modif_mail_to')) {
        warn "Couldn't get recipient address, please check your configuration.\n";
	warn "Mail will not be sent to the academic committee.\n";
	return undef;
    }

    unless($mail_from = get_conf($proposal->{-db}, 'proposal_modif_mail_from')) {
        warn "Couldn't get sender address, please check your configuration.\n";
	warn "Mail will not be sent to the academic committee.\n";
	return undef;
   }
    
    # Here goes my mail-processing mini-template-engine!
    for my $key (keys %mail_subst) {
        $mail =~ s/__${key}__/$mail_subst{$key}/gs;
    }
    
    unless ($smtp = Net::SMTP->new($smtp_host)) {
        warn "Couldn't contact SMTP server\n";
        warn "Mail will not be sent to the academic committee.\n";
        return undef;
    }

    $smtp->mail($mail_from);
    $smtp->to($mail_to);
    $smtp->data();
    $smtp->datasend($mail);
    $smtp->dataend();
    $smtp->quit();
    return 1;
}

=pod

=head3 $res = _send_mail_added_as_author($proposal, $new_auth, $this_auth,
$mail_tmpl, $mail_from);

Send a notification via email if a person is added as an author of some
proposal.

The arguments are:

=over 2

=item - $proposal

L<Comas::Proposal|Comas::Proposal> object of the current proposal.

=item - $new_auth

L<Comas::Person|Comas::Person> object of the new author of the proposal.

=item - $this_auth

L<Comas::Person|Comas::Person> object of the author that add the new author.

=item - $mail_tmpl

Filename of the email template with full path.

=item - $mail_from

Sender of the notification, normaly proposal_new_mail_from configuration value.

=back

This function also needs the following configuration value: smtp_host (if isn't
defined 127.0.0.1 is used).

The C<$res> retrun value is undef in case of an error or true if successful.

=cut

sub _send_mail_added_as_author {
    my ($proposal, $new_auth, $this_auth, $mail_tmpl, $mail_from, $mail_to,
	%prop_data, $mail, %mail_subst, $smtp_host, $smtp_conn);
    $proposal = shift;
    $new_auth = shift;
    $this_auth = shift;
    $mail_tmpl = shift;
    $mail_from = shift;

    %prop_data = $proposal->get_data;
    $mail_to = $new_auth->get_email;

    unless (-r $mail_tmpl and open(TMPL,'<', $mail_tmpl)) {
	warn "Could not open mail template ($mail_tmpl): $!\n";
	warn "New coauthor will not be notified\n";
	return undef;
    }
    $mail = join('', <TMPL>);
    close(TMPL);

    %mail_subst=(FROM => $mail_from,
		 NEW_NAME=>$new_auth->get_firstname.' '.$new_auth->get_famname,
		 NEW_MAIL => $mail_to,
		 THIS_NAME => $this_auth->get_firstname . ' ' .
		     $this_auth->get_famname,
		 THIS_MAIL => $this_auth->get_email,
		 PROP_TIT => $proposal->get_title,
		 PROP_ID => $proposal->get_id);

    $smtp_host = get_conf($proposal->{-db}, 'smtp_host') || '127.0.0.1';

    # Here goes my mail-processing mini-template-engine!
    for my $key (keys %mail_subst) {
        $mail =~ s/__${key}__/$mail_subst{$key}/gs;
    }
    
    unless ($smtp_conn = Net::SMTP->new($smtp_host)) {
        warn "Couldn't contact SMTP server\n";
        warn "New coauthor will not be notified.\n";
        return undef;
    }

    $smtp_conn->mail($mail_from);
    $smtp_conn->to($mail_to);
    $smtp_conn->data();
    $smtp_conn->datasend($mail);
    $smtp_conn->dataend();
    $smtp_conn->quit();
    return 1;    

}

=pod

=head3 $res = _send_new_proposal($proposal, $mail_tmpl, $mail_from);

Send a notification via email for each new proposal.

The arguments are:

=over 2

=item - $proposal

L<Comas::Proposal|Comas::Proposal> object of the new proposal.

=item - $mail_tmpl

Filename of the email template with full path.

=item - $mail_from

Sender of the notification, usually proposal_new_mail_from configuration value.

=back

This function also needs the following configuration value: smtp_host (if isn't
defined 127.0.0.1 is used).

The C<$res> retrun value is undef in case of an error or true if successful.

=cut

sub _send_mail_new_proposal {
    my ($mail, %mail_subst, $smtp_host, $mail_to, $smtp, $mail_from,
	$proposal, $mail_tmpl, $author, %prop_data);
    $proposal = shift;
    $mail_tmpl = shift;
    $mail_from = shift;

    %prop_data = $proposal->get_data;

    if (my ($author_id) = $proposal->get_authors) {
	# As this mail is sent only when the proposal is registered as new,
	# there can be only one registered author - Here we just got his ID,
	# now we create the Person object to get his data
	$author = Comas::Person->new(-db=>$proposal->{-db}, -id=>$author_id);
    }

    $mail_to = $author->get_email;

    unless ($author) {
	warn "Couldn't get required author information\n";
	warn "Confirmation mail for new proposal will not be sent\n";
	return undef;
    }

    unless (-r $mail_tmpl and open(TMPL, '<', $mail_tmpl)) {
	warn "Could not open mail template ($mail_tmpl): $!\n";
	warn 'Mail will not be sent to the academic committee.';
	return undef;
    }
    $mail = join('', <TMPL>);
    close(TMPL);
    
    %mail_subst=(FROM => $mail_from,
		 NAME => $author->get_firstname . ' ' . $author->get_famname,
		 MAIL => $mail_to,
		 PROP_ID => $prop_data{-id},
		 TITLE => $prop_data{-title},
		 TRACK => $proposal->{-db}->getCatDescr('track',
							$prop_data{-track_id}),
		 PROP_TYPE => $proposal->{-db}->getCatDescr('prop_type',
						  $prop_data{-prop_type_id}),
		 ABSTRACT => $prop_data{-abstract});

    $smtp_host = get_conf($proposal->{-db}, 'smtp_host') || '127.0.0.1';

    # Here goes my mail-processing mini-template-engine!
    for my $key (keys %mail_subst) {
        $mail =~ s/__${key}__/$mail_subst{$key}/gs;
    }
    
    unless ($smtp = Net::SMTP->new($smtp_host)) {
        warn "Couldn't contact SMTP server\n";
        warn "Mail will not be sent to the academic committee.\n";
        return undef;
    }

    $smtp->mail($mail_from);
    $smtp->to($mail_to);
    $smtp->data();
    $smtp->datasend($mail);
    $smtp->dataend();
    $smtp->quit();
    return 1;    
}

1;

=pod

=head1 SEE ALSO

L<Comas::HTML|Comas::HTML> module documentation

=head1 AUTHOR

Gunnar Wolf, gwolf@gwolf.cx

Manuel Rabade, mig@mig-29.net

Comas has been developed for CONSOL, Congreso Nacional de Software Libre,
http://www.consol.org.mx/

=head1 COPYRIGHT

Copyright 2003 Gunnar Wolf and Manuel Rabade

This library is free software, you can redistribute it and/or modify it
under the terms of the GPL version 2 or later.

=cut


# $Log: authors.pm,v $
# Revision 1.24  2004/11/12 05:44:57  gwolf
# Added the functionality to be able to handle more than one file per proposal and store it in the DB, not in separate files.
#
# Revision 1.23  2004/07/09 06:22:39  mig
# Fix small syntax errors in POD's
#
# Revision 1.22  2004/07/08 00:15:42  gwolf
# Handling Comas' and the conference's base URL in the configuration,
# not hard-coded in the HTML templates themselves
#
# Revision 1.21  2004/07/07 05:32:49  mig
# Added the documentation for the methods and functions.
#
# Revision 1.20  2004/06/25 02:30:59  gwolf
# Send a mail to a person when added as a coauthor to a proposal
#
# Revision 1.19  2004/04/14 13:32:38  gwolf
# Smaller typo/bug fixes.
#
# Revision 1.18  2004/04/07 21:33:31  gwolf
# Added the logic to send a mail when a new proposal is received (only
# if proposal_new_mail_from is defined in config)
#
# Revision 1.17  2004/04/06 05:02:21  gwolf
# Send a confirmation mail when a new proposal is received (only if the
# 'proposal_new_mail_from' variable is set in the configuration table)
#
# Revision 1.16  2004/02/04 18:09:54  mig
# - Restringo tipos de ponencia (pa las magistrales)
#
# Revision 1.15  2004/01/20 17:49:10  mig
# - Evitando warinings :)
#
# Revision 1.14  2004/01/11 04:56:35  mig
# - Agrego _send_proposal_file_mail y _send_proposal_modif_mail para
#   notificaciones de correo.
# - La información de achivos la saco de _get_file_info y no ahi mismo (menos
#   codigo :-D )
#
# Revision 1.13  2003/12/21 07:31:14  mig
# - Agrego confirmacion antes de eliminar una ponencia.
# - Simplifico la actualización de información de autores.
#
# Revision 1.12  2003/12/21 04:30:17  mig
# - Ya se normalizan los paths al cargar la configuracion cuando se crea el
#   objeto, menos codigo :)
#
# Revision 1.11  2003/12/20 04:14:51  mig
# - Agrego tags Id y Log que expanda el CVS
#
