# Copyright (c) 2008-2010 bivio Software, Inc. All Rights Reserved. # # Visit http://www.bivio.biz for more info. # # This library is free software; you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as # published by the Free Software Foundation; either version 2.1 of the # License, or (at your option) any later version. # # This library 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 # Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this library; If not, you may get a copy from: # http://www.opensource.org/licenses/lgpl-license.html # # $Id: MailForm.pm,v 1.35 2011/02/22 00:18:35 nagler Exp $ package Bivio::Biz::Model::MailForm; use strict; use Bivio::Base 'Biz.FormModel'; our($VERSION) = sprintf('%d.%02d', q$Revision: 1.35 $ =~ /\d+/g); my($_EA) = b_use('Type.EmailArray'); my($_I) = b_use('Mail.Incoming'); my($_O) = b_use('Mail.Outgoing'); my($_RFC) = b_use('Mail.RFC822'); my($_MRW) = b_use('Type.MailReplyWho'); my($_ARM) = b_use('Action.RealmMail'); my($_MA) = b_use('Mail.Address'); my($_QUERY_WHO) = 'to'; my($_MWRT) = b_use('Type.MailWantReplyTo'); my($_BRM) = b_use('Action.BoardRealmMail'); my($_FM) = b_use('Type.FormMode'); sub VIEW_CLASS { return (shift->simple_package_name =~ /(.+)Form/)[0]; } sub execute_cancel { my($self) = @_; $self->clear_errors; return shift->internal_return_value; } sub execute_empty { my($self) = @_; my($m) = $self->get('realm_mail'); my($in) = $m && $_I->new($m); my($to, $cc) = $self ->internal_get_reply_incoming($in) ->get_reply_email_arrays( $self->internal_query_who, $self->get(qw(realm_email realm_emails)), $self->req, ); $self->internal_put_field( subject => $in ? $in->get_reply_subject : '', to => $to, cc => $cc, ); return; } sub execute_ok { my($self) = @_; my($req) = $self->req; my($id) = $req->unsafe_get_nested(qw(Model.RealmMail message_id)); my($to, $cc, $realm_email, $realm_emails) = $self->get(qw(to cc realm_email realm_emails)); my($board_email) = $_BRM->format_email_for_realm($req); my($from) = $self->internal_format_from($realm_email); my($from_email) = $_MA->parse($from); unless ($from_email) { $self->internal_put_error(from_email => 'INVALID_SENDER'); return; } my($sender) = $self->internal_format_sender($realm_email); my($reply_to) = $self->internal_format_reply_to($realm_email); my($other_recipients, $removed_sender) = _remove_emails($to->append($cc), $realm_emails); my($removed_board); ($other_recipients, $removed_board) = _remove_emails($other_recipients, $board_email); my($board_only) = $removed_board || $self->unsafe_get('board_only') || (!$removed_sender && $self->unsafe_get('board_always')); if ($board_only) { if ($removed_sender) { $to = $to->exclude($realm_emails); $cc = $cc->exclude($realm_emails); } unless ($removed_board) { if ($to->as_length) { $cc = $cc->append($board_email); } else { $to = $to->append($board_email); } } } $self->internal_put_field(headers => { _from => $from, _recipients => $other_recipients->as_literal, Sender => $sender, To => $to->as_literal, $reply_to ? ('Reply-To' => $reply_to) : (), $cc->as_length ? (Cc => $cc->as_literal) : (), Subject => $self->internal_format_subject, 'Message-Id' => $_O->generate_message_id($req), $id ? ('In-Reply-To' => $_RFC->format_angle_brackets($id)) : (), }); my($msg) = $self->internal_format_incoming; if ($board_only) { $msg = $self->internal_send_to_board($msg); } elsif ($removed_sender) { $msg = $self->internal_send_to_realm($msg); } $_O->new($msg) ->set_recipients($other_recipients->as_literal) ->set_envelope_from($from_email) ->enqueue_send($req) if $other_recipients->as_length; return $self->internal_return_value; } sub get_realm_emails { my($self) = @_; return $self->new_other('EmailAlias')->get_all_emails; } sub internal_format_from { my($self, $realm_email) = @_; return $_RFC->format_mailbox( $self->new_other('EmailAlias') ->format_realm_as_incoming($self->req('auth_user')), $self->req(qw(auth_user display_name)), ); } sub internal_format_incoming { my($self) = @_; return b_use('UI.View')->render($self->VIEW_CLASS . '->form_imail', $self->req); } sub internal_format_reply_to { my($self, $realm_email) = @_; return $_MWRT->is_set_for_realm($self->req) ? $_RFC->format_mailbox( $realm_email, $self->req(qw(auth_realm owner display_name)), ) : (); } sub internal_format_sender { my($self, $realm_email) = @_; return $self->new_other('EmailAlias')->format_realm_as_sender($realm_email); } sub internal_format_subject { return shift->get('subject'); } sub internal_get_reply_incoming { my($self, $in) = @_; return $in || $_I; } sub internal_initialize { my($self) = @_; return $self->merge_initialize_info($self->SUPER::internal_initialize, { version => 1, require_context => 1, $self->field_decl( visible => [ [qw(to EmailArray IS_SPECIFIED)], [qw(cc EmailArray)], [qw(subject RealmMail.subject NOT_NULL)], [qw(body TextArea NOT_NULL)], @{$self->map_attachments(sub {[shift, 'FileField']})}, [qw(board_only Boolean)], ], other => [ [qw(headers Hash)], 'RealmMail.realm_file_id', 'RealmMail.thread_root_id', [qw(is_new Boolean NOT_NULL)], [qw(realm_mail Model.RealmMail)], [qw(realm_email Email)], [qw(realm_emails EmailArray)], [qw(board_always Boolean)], [qw(from_email Email)], ], ), }); } sub internal_pre_execute { my($self) = @_; my($rml) = $self->new_other('RealmMailList'); my($edit) = $_FM->setup_by_list_this($rml, 'RealmMail')->eq_edit; $self->internal_put_field( realm_mail => $self->ureq('Model.RealmMail'), is_new => $edit ? 0 : 1, realm_emails => $self->get_realm_emails, realm_email => $self->new_other('EmailAlias') ->format_realm_as_incoming, map( ($_ => $edit && $rml->get($_)), qw(RealmMail.realm_file_id RealmMail.thread_root_id), ), ); return shift->SUPER::internal_pre_execute(@_); } sub internal_query_who { return $_MRW->unsafe_from_any((shift->req('query') || {})->{$_QUERY_WHO}) || $_MRW->REALM; } sub internal_return_value { return { task_id => 'next', }; } sub internal_send_to_board { my($self, $rfc822) = @_; my($req) = $self->req; $_BRM->execute_receive($req, $rfc822); return $req->get('Model.RealmMail')->get_rfc822; } sub internal_send_to_realm { my($self, $rfc822, $board_only) = @_; my($req) = $self->req; $_ARM->execute_receive($req, $rfc822); return $req->get('Model.RealmMail')->get_rfc822; } sub is_reply { return shift->unsafe_get('RealmMail.realm_file_id') ? 1 : 0; } sub mail_header_from { return shift->get('headers')->{_from}; } sub mail_headers { my($h) = shift->get('headers'); return [map(/^_/ ? () : [$_ => $h->{$_}], sort(keys(%$h)))]; } sub mail_envelope_recipients { return shift->get('headers')->{_recipients}; } sub map_attachments { my(undef, $op) = @_; return [map($op->("attachment$_"), 1..3)]; } sub reply_query { my(undef, $who, $model) = @_; return { 'ListQuery.this' => $model ? $model->get('RealmMail.realm_file_id') : ['RealmMail.realm_file_id'], $_QUERY_WHO => lc($_MRW->from_any($who)->as_uri), }; } sub validate { my($self) = @_; shift->SUPER::validate(@_); my($type) = $self->get_field_type('cc'); if ( $self->field_error_equals(to => 'UNSPECIFIED') && $type->is_specified($self->unsafe_get('cc')) ) { $self->internal_clear_error('to'); $self->internal_put_field( to => $self->get('cc'), cc => $type->from_literal_or_die(''), ); } return; } sub _remove_emails { my($email_array, $to_remove) = @_; my($res) = $email_array->exclude($to_remove); return ($res, $res->as_length != $email_array->as_length); } 1;