|/eg;
$$message =~ s/\r?\n/
/g; # That space keeps IE from condensing multiple
's into 1. It is only needed where you have
, and only inside , but the necessary regex would slow the conversion down quite a bit.
$$message =~ s/^( +)/' ' x length $1/gem;
$message;
}
END_OF_SUB
# Takes a single argument - the temp ID.
# Returns an error message if messsages can't be attached, undef if everything is good to go.
$COMPILE{cant_attach} = __LINE__ . <<'END_OF_SUB';
sub cant_attach {
my @args = @_;
GT::Plugins->dispatch($CFG->{admin_root_path} . '/Plugins', 'message_cant_attach', sub { return _plg_cant_attach(@args) });
}
sub _plg_cant_attach {
$Attachment_Max = undef;
my $temp_id = shift;
if (!$CFG->{allow_message_attachments}) {
return GForum::language('ATTACHMENTS_NOT_ALLOWED');
}
if ($CFG->{message_attachments_max_size}) {
my $total_size = $DB->table('MessageAttachment')->_attachments_size;
if ($total_size >= $CFG->{message_attachments_max_size}) {
return GForum::language('ATTACHMENT_LIMIT_EXCEEDED');
}
$Attachment_Max = $CFG->{message_attachments_max_size} - $total_size;
$Attachment_Max = $CFG->{message_attachment_max_size} if $CFG->{message_attachment_max_size} < $Attachment_Max;
}
if ($CFG->{message_attachments_max_count}) {
my $count = $DB->table('MessageAttachment')->count + $DB->table('TempAttachment')->count({ tempatt_type => 'Message' });
if ($count >= $CFG->{message_attachments_max_count}) {
return GForum::language('ATTACHMENT_COUNT_EXCEEDED');
}
}
if ($temp_id and $CFG->{message_attachments}) {
my $count = $DB->table('TempAttachment')->count({ tempatt_msg_id => $temp_id });
if ($count >= $CFG->{message_attachments}) {
return GForum::language('ATTACHMENT_COUNT_EXCEEDED');
}
}
return;
}
END_OF_SUB
$COMPILE{generate_temp_id} = __LINE__ . <<'END_OF_SUB';
sub generate_temp_id { require GT::MD5; GT::MD5::md5_hex(time . $$ . rand(16000)) }
END_OF_SUB
$COMPILE{send} = __LINE__ . <<'END_OF_SUB';
sub send {
shift; # Discard the package name
uc $ENV{REQUEST_METHOD} eq 'POST' or die "Unable to send with a GET method";
my ($do, $func) = @_;
my $page = $func->{page};
my $user_id = $IN->param('user');
my $user_username = $IN->param('user_username') if not $user_id;
my $temp_id = $IN->param('temp_id');
my $recipient;
if ($user_id) {
$recipient = $DB->table('User')->get($user_id)
or return GForum::do_func($IN->param('reply_to') ? 'message_reply_write' : 'message');
}
elsif ($user_username) { # Try to work off the username
$recipient = $DB->table('User')->select({ user_username => $user_username })->fetchrow_hashref
or return GForum::do_func($IN->param('reply_to') ? 'message_reply_write' : 'message');
$user_id = $recipient->{user_id};
}
else {
$IN->param(tried_sending => 1);
return GForum::do_func($IN->param('reply_to') ? 'message_reply_write' : 'message');
}
$recipient->{user_accept_privmsg}
or return(
$page->{no_privmsg} => {
error => GForum::language('USER_NO_PRIVMSG', $recipient->{user_username})
}
);
my $message = $IN->param('msg_body');
if ($IN->param('advanced_editor')) {
$message = GForum::Convert::advanced_editor_convert($message);
}
$message =~ s/\s+$//; # Remove all trailing whitespace
$message .= "\n" . $USER->{user_signature} if $IN->param('msg_append_signature');
my $subject = $IN->param('msg_subject');
$subject = GForum::language("NO_SUBJECT") unless $subject =~ /[^\s\xa0]/; # \xa0 is Alt-0160 - a non-breaking space
my $ip = $ENV{REMOTE_ADDR};
my $style = $IN->param('msg_style');
$style = $USER->{user_default_message_style} || 3 if not defined $style or $style =~ /\D/;
if ($CFG->{message_style} < $style or $CFG->{message_style} == 2 and $style == 1) {
$style = $CFG->{message_style};
}
my $insert = {
to_user_id_fk => $user_id,
from_user_id_fk => $USER->{user_id},
msg_subject => $subject,
msg_body => $message,
msg_time => time,
msg_ip => $ip,
msg_username => $USER->{user_username},
msg_style => $style
};
my ($Message, $SentMessage) = ($DB->table('Message'), $DB->table('SentMessage'));
my $cols = $Message->cols;
for my $col (keys %$cols) {
next if $cols->{$col}->{protect} or exists $insert->{$col} or not defined(my $val = $IN->param($col));
$insert->{$col} = $val;
}
my $msg_id = ($DB->table('Message')->insert($insert) or die $GT::SQL::error)->insert_id;
$insert = {
msg_id => $msg_id,
to_user_id_fk => $user_id,
from_user_id_fk => $USER->{user_id},
msg_subject => $subject,
msg_body => $message,
msg_time => time,
msg_ip => $ip,
msg_username => $recipient->{user_username}
};
$cols = $SentMessage->cols;
for my $col (keys %$cols) {
next if $cols->{$col}->{protect} or exists $insert->{$col} or not defined(my $val = $IN->param($col));
$insert->{$col} = $val;
}
$SentMessage->insert($insert) or die $GT::SQL::error;
if (my $parent_id = $IN->param('reply_to')) {
$Message->update({ msg_status => REPLIED }, { msg_id => $parent_id, to_user_id_fk => $USER->{user_id} });
}
my @attach_errors;
my $ma = $DB->table('MessageAttachment');
# Get all the temporary attachments associated with this ID so that we can
# transfer the attachments from TempAttachment to MessageAttachment
my $sth = $DB->table('TempAttachment')->select('tempatt_id', { tempatt_msg_id => $temp_id });
while (my $tempatt_id = $sth->fetchrow_array) {
$ma->insert({ tempatt_id => $tempatt_id, msg_id_fk => $msg_id })
or push @attach_errors, delete $ma->{attachment_error};
}
my $fresh_msg = $DB->table('Message', 'User')->select({ msg_id => $msg_id })->fetchrow_hashref or die $GT::SQL::error; # By selecting it again, we make
# sure anything the subclass or plugins do is displayed.
$fresh_msg->{msg_body_text} = $fresh_msg->{msg_body};
normalize($fresh_msg);
@$fresh_msg{map "to_$_", keys %$recipient} = values %$recipient;
if ($recipient->{user_message_notify} and $recipient->{user_email}) {
plain_text(\$fresh_msg->{msg_body_text}, $fresh_msg); # Strip out markup and HTML
require GT::Mail::Editor;
my $email = GT::Mail::Editor->new(dir => "$CFG->{admin_root_path}/templates", template => ($recipient->{user_template} || $CFG->{default_template_set}));
$email->load("message.eml");
my $headers = $email->headers;
my %head;
while (my ($k, $v) = each %$headers) {
my $val = $v; # Copy it
$val = GForum::Template->parse("string", $fresh_msg, { string => $val });
$head{$k} = $val;
}
my $body = $email->body;
$body = GForum::Template->parse("string", $fresh_msg, { string => $body });
$CFG->{smtp_server} or $CFG->{mail_path} or die 'No mail path of SMTP server set!';
$head{To} ||= $recipient->{user_email};
$head{From} ||= $CFG->{admin_email};
require GT::Mail;
my $mailer = GT::Mail->new(
%head,
msg => $body,
($CFG->{smtp_server} ? (smtp => $CFG->{smtp_server}) : (sendmail => $CFG->{mail_path}))
);
local $@;
eval { $mailer->send };
if ($@ and $GForum::DEBUG || $CFG->{debug_level}) {
die $mailer->error;
}
}
return(
$page->{send} => {
%$fresh_msg,
(@attach_errors ? (attachment_errors => GForum::language('ATTACHMENT_FAILED', "
\n" . join '', map "$_->[0]: $_->[1]
\n", @attach_errors)) : ()),
}
);
}
END_OF_SUB
$COMPILE{download_attachment} = __LINE__ . <<'END_OF_SUB';
sub download_attachment {
shift; # Discard the package name
my ($do, $func) = @_;
my $page = $func->{page};
my $messatt_id;
$messatt_id = $IN->param('messatt_id') and my $attachment = $DB->table('MessageAttachment' => 'Message')->select({ messatt_id => $messatt_id, to_user_id_fk => $USER->{user_id} })->fetchrow_hashref
or return(
$page->{no_such_message_attachment} => {
error => GForum::language('ATTACHMENT_DOES_NOT_EXIST')
}
);
my $file = \do { local *FH; *FH };
my $dir = $attachment->{messatt_id} % 10;
my $filename = "$CFG->{message_attachment_directory}/$dir/$messatt_id";
unless (open $file, "<$filename") {
$DB->table('MessageAttachment')->delete($messatt_id);
return($page->{no_such_message_attachment}, { messatt_if => $messatt_id });
}
binmode $file;
binmode STDOUT;
print $IN->header(
-type => $attachment->{messatt_content},
"Content-Disposition" => \("attachment; filename=" . $IN->escape($attachment->{messatt_filename}) . "; size=$attachment->{messatt_size}")
);
{
local $\;
while (read($file, my $chunk, 4096)) {
print $chunk;
}
}
return;
}
END_OF_SUB
# Takes two arguments: A scalar reference to a non-normalized msg_body
# value, and the normalized Message,User hash it came from. Returns nothing.
$COMPILE{plain_text} = __LINE__ . <<'END_OF_SUB';
sub plain_text {
my ($str, $msg) = @_;
$$str =~ s/
/\n/g if $msg->{msg_style} >= 2;
$$str =~ s/<.*?>//g if $msg->{msg_style} >= 2;
$$str =~ s/\[(\s*(.*?)\s*)\]/if (exists $CFG->{markup_tags}->{lc $2} or lc $2 eq lc $CFG->{signature_markup_tag}) { "" } elsif (substr($1, 0, 1) eq ".") { "[" . substr($1, 1) . "]" } else { "[$1]" }/eg if $msg->{msg_style} % 2;
convert_signature($str, \$msg->{msg_signature});
return;
}
END_OF_SUB
sub normalize {
my ($msg, $sent) = @_;
GT::Plugins->dispatch($CFG->{admin_root_path} . '/Plugins', "message_normalize", \&_plg_normalize, $msg, $sent);
}
sub _plg_normalize {
my $msgs = ref $_[0] eq 'ARRAY' ? shift : [shift];
my $sent = shift;
my $blank;
my $literal = $IN->param('literal');
for my $msg (@$msgs) {
$msg->{msg_date} = GForum::date($msg->{msg_time});
if ($msg->{msg_style} < 2 or $literal) {
escape_html($msg->{msg_body});
}
if ($msg->{msg_style} % 2 and not $literal) {
convert_markup(\$msg->{msg_body});
}
if ($msg->{user_id}) {
require GForum::User;
GForum::User::normalize($msg);
}
else { # The user has been deleted
require GForum::User;
$blank ||= GForum::User::blank_user({
user_username => 'username',
user_title => \GForum::language('USER_DELETED'),
user_signature => ''
});
@$msg{keys %$blank} = values %$blank;
$msg->{user_username} = $msg->{msg_username};
$msg->{user_signature} = $msg->{msg_signature_deleted};
}
my $signature = $msg->{user_signature};
unless ($CFG->{signature_allow_html} and not $literal) {
escape_html($signature);
}
if ($CFG->{signature_allow_markup} == 2 and not $literal) {
convert_markup(\$signature);
}
elsif ($CFG->{signature_allow_markup} and not $literal) {
local $GForum::Convert::No_Image = 1;
convert_markup(\$signature);
}
if (not $CFG->{signature_allow_html} and not $CFG->{signature_allow_markup} or $literal) {
$signature =~ s/ / /g;
}
convert_signature(\$msg->{msg_body}, \$signature);
$msg->{msg_body} =~ s/\r?\n/
/g; # That space keeps IE from condensing multiple
's into 1. It is only needed where you have
, but that regex would slow the converter down quite a bit.
$msg->{msg_body} =~ s/^( +)/' ' x length $1/gem;
my $body = $msg->{msg_body};
$msg->{msg_body} = \$body;
}
attachments($msgs) unless $sent; # Sent messages don't have attachments set.
$msgs
}
# Takes a array ref of hash refs and sets $hash->{msg_attachments} to an array
# ref of hash refs. The hash refs are the attachments of the message. If
# "msg_has_attachments" is not set, nothing is done. There is no returned value.
sub attachments {
my $msgs = ref $_[0] eq 'ARRAY' ? shift : [shift];
my $sth = $DB->table('MessageAttachment')->select({
msg_id_fk => [map { $_->{msg_has_attachments} ? $_->{msg_id} : () } @$msgs]
});
my %att;
while (my $att = $sth->fetchrow_hashref) {
$att->{messatt_filename_escaped} = escape_string($IN->escape($att->{messatt_filename}));
push @{$att{$att->{msg_id_fk}}}, $att;
}
for my $msg (@$msgs) {
$msg->{msg_has_attachments} and exists $att{$msg->{msg_id}} or $msg->{msg_num_attachments} = 0, next;
my @attachments = @{$att{$msg->{msg_id}}};
$msg->{msg_attachments} = \@attachments;
$msg->{msg_num_attachments} = @attachments;
}
return;
}
1;