# ================================================================== # Gossamer Forum - Advanced web community # # Website : http://gossamer-threads.com/ # Support : http://gossamer-threads.com/scripts/support/ # Revision : $Id: Write.pm,v 1.54.2.13 2004/08/10 20:23:53 jagerman Exp $ # # Copyright (c) 2003 Gossamer Threads Inc. All Rights Reserved. # Redistribution in part or in whole strictly prohibited. Please # see LICENSE file for full details. # ================================================================== # # This file handles everything associated with writing/editing a post. # package GForum::Post::Write; use strict; use vars qw/$Attachment_Max/; use GForum qw/:user :forum $DB $IN $CFG $USER $GUEST %HIDDEN/; use GForum::Post; use GT::Plugins; # GForum::Post loads all of the other modules we may need sub attachment_upload { my $temp_id = $IN->param('temp_id'); my $file = $IN->param("post_attachment") or return GForum::do_func($IN->param('redo')); my ($filename, $ext) = $file =~ m{(?:^|[\\/])([^\\//]+?(\.[^\\/.]+)?)$}; require GT::MIMETypes; my $content_type = GT::MIMETypes->guess_type(".$ext"); my $attach = $DB->table('TempAttachment'); $attach->delete(GT::SQL::Condition->new(tempatt_expiry => '<=' => time)); my $error; my $forum_id; my $post_id; my ($forum, $parent, $post) = (scalar $IN->param('forum'), scalar $IN->param('parent_post_id'), scalar $IN->param('post')); if ($forum and not $parent and not $post) { # A new post $forum_id = $forum; } elsif ($parent and not $post) { # A reply $forum_id = $DB->table('Post')->get($parent, 'ARRAY', ['forum_id_fk'])->[0]; } elsif ($post and not $parent) { # An edit $forum_id = $DB->table('Post')->get($post, 'ARRAY', ['forum_id_fk'])->[0]; $post_id = $post; } else { $GForum::Template::VARS{attachment_error} = GForum::language('ATTACHMENT_NOT_ALLOWED'); return GForum::do_func($IN->param('redo')); } unless ($DB->table('Forum')->count({ forum_id => $forum_id, forum_allow_attachments => 1 })) { $GForum::Template::VARS{attachment_error} = GForum::language('ATTACHMENT_NOT_ALLOWED'); return GForum::do_func($IN->param('redo')); } my $inline = $IN->param('post_attachment_inline') ? 1 : 0; $attach->insert(Post => { tempatt_msg_id => $temp_id, tempatt_filename => $filename, tempatt_content => $content_type, tempatt_fh => $file, forum_id => $forum_id, ($post_id ? (post_id => $post_id) : ()), tempatt_inline => $inline }) or $error = $attach->{attachment_error}; $GForum::Template::VARS{attachment_error} = $error if $error; GForum::do_func($IN->param('redo')); } sub attachment_delete { my $att_id = $IN->param('att_id'); my $type = $IN->param('att_type'); if ($type eq 'temp') { # It's a temporary attachment we need to delete. $DB->table('TempAttachment')->delete($att_id); } elsif ($type eq 'post') { my $post = $DB->table('PostAttachment' => 'Post')->select({ postatt_id => $att_id })->fetchrow_hashref; if ($USER and $post and ($USER->{user_id} == $post->{user_id_fk} or GForum::Authenticate::auth('forum_permission', $post->{forum_id_fk}) >= FORUM_PERM_MODERATOR)) { $DB->table('PostAttachment')->delete($att_id); } else { return GForum::do_func('permission_denied'); } } else { die "Unknown attachment type '$type'"; } GForum::do_func($IN->param('redo')); } sub write { shift; my ($do, $func) = splice @_, 0, 2; my $page = $func->{page}; my $forum_id = $IN->param('forum'); my $forum; unless ($forum_id and $forum = $DB->table('Forum', 'Category')->select({ forum_id => $forum_id })->fetchrow_hashref) { return( $page->{no_such_forum} => { error => GForum::language('FORUM_DOES_NOT_EXIST') } ); } require GForum::Forum; GForum::Forum::normalize($forum); my $style = $IN->param('post_style'); $style = $USER ? $USER->{user_default_post_style} : 3 if not defined $style; if ($forum->{forum_style} < $style or $forum->{forum_style} == 2 and $style == 1) { $style = $forum->{forum_style}; } my $temp_id; my $attach = []; if ($temp_id = $IN->param('temp_id')) { my $ta = $DB->table('TempAttachment'); # Handle any attachment inline/non-inline changes: my (@add_inline_temp, @rem_inline_temp); for my $k ($IN->param) { if ($k =~ /^att_deinline-(\d+)-temp$/ and !$IN->param("att_inline-$1-temp")) { push @rem_inline_temp, $1; } elsif ($k =~ /^att_inline-(\d+)-temp$/ and !$IN->param("att_deinline-$1-temp")) { push @add_inline_temp, $1; } } $ta->update({ tempatt_inline => 1 }, { tempatt_id => \@add_inline_temp, tempatt_msg_id => $temp_id }) if @add_inline_temp; $ta->update({ tempatt_inline => 0 }, { tempatt_id => \@rem_inline_temp, tempatt_msg_id => $temp_id }) if @rem_inline_temp; $ta->select_options('ORDER BY tempatt_id'); my $sth = $ta->select({ tempatt_msg_id => $temp_id }); while (my $rec = $sth->fetchrow_hashref) { for (keys %$rec) { if (s/^temp//) { $rec->{$_} = delete $rec->{"temp$_"}; } } $rec->{att_type} = "temp"; push @$attach, $rec; } } else { $temp_id = generate_temp_id(); } my @anonymous; if (!$USER) { @anonymous = @{$DB->table('User')->select({ user_status => ANONYMOUS, user_enabled => 1 })->fetchall_hashref}; if (!@anonymous) { return($page->{anonymous_not_configured} => { error => GForum::language('POST_ANONYMOUS_DISABLED') }); } elsif (my $anonymous = $IN->param('anon_id')) { for (@anonymous) { $_->{selected} = 1, last if $_->{user_id} == $anonymous; } } } my $post_subject = $IN->param('post_subject') || ''; my $post_message = $IN->param('post_message') || ''; my $orig_post_message; my %browser = GForum::browser_tags(); my $adv_allowed = ( $browser{is_ie} and $browser{ie_version} >= 5.5 or $browser{is_mozilla} and $browser{mozilla_version} >= 1.4 ); if ($post_message and $IN->param('basic_editor_switch')) { $post_message = GForum::Convert::advanced_editor_convert($post_message); } elsif ( ($IN->param('advanced_editor_switch') or not $IN->param('advanced_editor')) and ( ($post_message and $IN->param('advanced_editor_switch')) or ($IN->param('advanced_editor') and $adv_allowed) or ($USER and $USER->{user_advanced_editor} and not $IN->param('basic_editor') and $adv_allowed) ) ) { $orig_post_message = $post_message; _post_message_html(\$post_message, $style >= 2); } my $can_attach = not cant_attach({ forum_id => $forum_id, temp_id => $temp_id }); my $post_append_sig = $IN->param('post_append_signature'); $post_append_sig = 1 if not $post_subject and not $post_message; my $post_reply_notify = $IN->param('post_reply_notify'); if (not($post_subject or $post_message) and $USER) { $post_reply_notify = $USER->{user_default_reply_notify}; } my $sticky = 0; if ($USER and $USER->{user_forum_permission} >= FORUM_PERM_MODERATOR) { $sticky = 1 if $IN->param('post_sticky'); } my %page_data = ( temp_id => $temp_id, %$forum, forum_style_selected => $style, post_subject => $post_subject, orig_post_message => $orig_post_message, post_message => $post_message, post_icon => scalar $IN->param('post_icon'), advanced_editor => scalar $IN->param('advanced_editor'), basic_editor => scalar $IN->param('basic_editor'), attachments => $attach, num_attachments => scalar @$attach, can_attach => $can_attach, post_reply_notify => $post_reply_notify, post_append_signature => $post_append_sig, post_sticky => $sticky, ($USER ? ( alias_username => scalar $IN->param('alias_username') ) : ( anonymous => \@anonymous, post_anonymous_email => scalar $IN->param('post_anonymous_email'), guest_username => scalar $IN->param('guest_username') ) ) ); my $cols = $DB->table('Post')->cols; for my $col (keys %$cols) { next if $cols->{$col}->{protect} or exists $page_data{$col} or not defined(my $val = $IN->param($col)); $page_data{$col} = $val; } return($page->{write} => \%page_data); } sub reply_write { shift; my ($do, $func) = splice @_, 0, 2; my $page = $func->{page}; my $parent; my $parent_id = $IN->param('parent_post_id') or return die "No post ID entered"; # Get the parent post or print an error page. my $parent_sth = $DB->table('Post', 'User')->select(left_join => { post_id => $parent_id }) or die $GT::SQL::error; unless ($parent_id and $parent = $parent_sth->fetchrow_hashref) { return( $page->{no_such_post} => { error => GForum::language('POST_DOES_NOT_EXIST') } ); } elsif ($parent->{post_deleted}) { return( $page->{post_deleted} => { error => GForum::language('POST_IS_DELETED') } ); } if ($USER and $USER->{user_forum_permission} < FORUM_PERM_MODERATOR) { # If you have moderator privileges you can post whether or not the post is locked, so # these checks only happen if you don't have moderator privileges. my $locked; if ($parent->{post_root_id}) { # The parent isn't the root post $locked = $DB->table('Post')->get($parent->{post_root_id}, 'ARRAY', ['post_locked'])->[0]; } else { # If the parent is the root post this saves a select to get the root post $locked = $parent->{post_locked}; } if ($locked) { return($page->{locked}, { error => GForum::language('POST_LOCKED') }); } } my $forum = $DB->table('Forum', 'Category')->select({ forum_id => $parent->{forum_id_fk} })->fetchrow_hashref; require GForum::Forum; GForum::Forum::normalize($forum); my ($err_code, $error) = shift; $error = sprintf GForum::language($err_code), @_ if $err_code; my $style = $IN->param('post_style'); $style = $USER ? $USER->{user_default_post_style} : 3 if not defined $style; if ($forum->{forum_style} < $style or $forum->{forum_style} == 2 and $style == 1) { $style = $forum->{forum_style}; } my $parent_body = $parent->{post_message}; GForum::Post::normalize($parent); my $cols = $DB->table('Post')->{schema}->{cols}; for (keys %$parent) { $parent->{"parent_$_"} = delete $parent->{$_} if $cols->{$_}; } my $subject; unless ($subject = $IN->param('post_subject')) { my $re = GForum::language('POST_REGARDING'); if ($CFG->{post_reply_position} eq 'end') { if ($CFG->{post_reply_subject_username} and $CFG->{post_reply_subject_username} eq 'beginning') { $subject = $parent->{parent_post_subject}; $subject =~ s/^(?:\s*\[.*?\]\s*)?/[$parent->{parent_post_username}] /; $subject =~ s/\s*(?:\Q$re\E\s*)?$/$re/; } elsif ($CFG->{post_reply_subject_username} and $CFG->{post_reply_subject_username} eq 'after_re') { ($subject = $parent->{parent_post_subject}) =~ s/\s*(?:(?:\s*\[.*?\]\s*)?\s*\Q$re\E)?$/ \[$parent->{parent_post_username}]$re/; } elsif ($CFG->{post_reply_subject_username} and $CFG->{post_reply_subject_username} eq 'end') { ($subject = $parent->{parent_post_subject}) =~ s/\s*(?:\Q$re\E\s*)?(?:\[.*?\]\s*)?$/$re [$parent->{parent_post_username}]/; } else { ($subject = $parent->{parent_post_subject}) =~ s/\s*(?:\Q$re\E\s*)?$/$re/; } } else { if ($CFG->{post_reply_subject_username} and $CFG->{post_reply_subject_username} eq 'beginning') { ($subject = $parent->{parent_post_subject}) =~ s/^\s*(?:(?:\[.*?\]\s*)?\Q$re\E)?/[$parent->{parent_post_username}] $re/; } elsif ($CFG->{post_reply_subject_username} and $CFG->{post_reply_subject_username} eq 'after_re') { ($subject = $parent->{parent_post_subject}) =~ s/^\s*(?:\Q$re\E(?:\s*\[.*?\]\s*)?)?/$re\[$parent->{parent_post_username}] /; } elsif ($CFG->{post_reply_subject_username} and $CFG->{post_reply_subject_username} eq 'end') { ($subject = $parent->{parent_post_subject}) =~ s/^\s*(?:\Q$re\E)?/$re/; $subject =~ s/\s*(\[.*?\])?\s*$/ [$parent->{parent_post_username}]/; } else { ($subject = $parent->{parent_post_subject}) =~ s/^\s*(?:\Q$re\E)?/$re/; } } } my $temp_id; my $attach = []; if ($temp_id = $IN->param('temp_id')) { my $ta = $DB->table('TempAttachment'); # Handle any attachment inline/non-inline changes: my (@add_inline_temp, @rem_inline_temp); for my $k ($IN->param) { if ($k =~ /^att_deinline-(\d+)-temp$/ and !$IN->param("att_inline-$1-temp")) { push @rem_inline_temp, $1; } elsif ($k =~ /^att_inline-(\d+)-temp$/ and !$IN->param("att_deinline-$1-temp")) { push @add_inline_temp, $1; } } $ta->update({ tempatt_inline => 1 }, { tempatt_id => \@add_inline_temp, tempatt_msg_id => $temp_id }) if @add_inline_temp; $ta->update({ tempatt_inline => 0 }, { tempatt_id => \@rem_inline_temp, tempatt_msg_id => $temp_id }) if @rem_inline_temp; $ta->select_options('ORDER BY tempatt_id'); my $sth = $ta->select({ tempatt_msg_id => $temp_id }); while (my $rec = $sth->fetchrow_hashref) { for (keys %$rec) { if (s/^temp//) { $rec->{$_} = delete $rec->{"temp$_"}; } } $rec->{att_type} = "temp"; push @$attach, $rec; } } else { $temp_id = generate_temp_id(); } my @anonymous; if (!$USER) { @anonymous = @{$DB->table('User')->select({ user_status => ANONYMOUS, user_enabled => 1 })->fetchall_hashref}; if (!@anonymous) { return($page->{anonymous_not_configured} => { error => GForum::language('POST_ANONYMOUS_DISABLED') }); } elsif (my $anonymous = $IN->param('anon_id')) { for (@anonymous) { $_->{selected} = 1, last if $_->{user_id} == $anonymous; } } } my $can_attach = not cant_attach({ forum_id => $forum->{forum_id}, temp_id => $temp_id }); my $post_subject = $IN->param('post_subject') || ''; my $post_message = $IN->param('post_message') || ''; my $orig_post_message; my $quoted; if (!$post_message and $IN->param('quote') and $forum->{forum_style} % 2) { $parent_body =~ s/
/\n/g; $parent_body =~ s/\n?\[\s*\Q$CFG->{markup_signature_tag}\E\s*\]//g; # Inline attachments can't be carried forward to a reply: $parent_body =~ s/\[\s*inline\s+("[^"]*"|'[^']*'|[^]\s]+)\s*\]//g; if ($parent->{parent_post_style} % 2) { $style = $parent->{parent_post_style}; } elsif ($parent->{parent_post_style}) { # HTML-only mode $style = 3; # Both mode $parent_body =~ s/\[([^\]]*)\]/[.$1]/g; # Escape markup tags } else { $style = 1; # Markup mode - the parent was a plain text. $parent_body =~ s/\[([^\]]*)\]/[.$1]/g; # Escape markup tags } my $reply_tag = 'reply'; unless ($CFG->{markup_tags}->{reply}) { if ($CFG->{markup_tags}->{'répondre'}) { # Hack :( - GForum 2 needs a much better translation mechanism $reply_tag = 'répondre'; } } $post_message = "[$reply_tag]$parent_body\[/$reply_tag]"; $quoted = 1; } my %browser = GForum::browser_tags(); my $adv_allowed = ( $browser{is_ie} and $browser{ie_version} >= 5.5 or $browser{is_mozilla} and $browser{mozilla_version} >= 1.4 ); if ($post_message and $IN->param('basic_editor_switch')) { $post_message = GForum::Convert::advanced_editor_convert($post_message); } elsif ( ($IN->param('advanced_editor_switch') or not $IN->param('advanced_editor')) and ( ($post_message and $IN->param('advanced_editor_switch')) or ($IN->param('advanced_editor') and $adv_allowed) or ($USER and $USER->{user_advanced_editor} and not $IN->param('basic_editor') and $adv_allowed) ) ) { $orig_post_message = $post_message; _post_message_html(\$post_message, $style >= 2); } my $post_append_sig = $IN->param('post_append_signature'); $post_append_sig = 1 if not $post_subject and not $post_message or $quoted; my $post_reply_notify = $IN->param('post_reply_notify'); if ((!$post_subject and !$post_message or $quoted) and $USER) { $post_reply_notify = $USER->{user_default_reply_notify}; } my %page_data = ( temp_id => $temp_id, %$parent, %$forum, ($error ? (error => $error) : ()), forum_style_selected => $style, post_subject => $subject, post_message => $post_message, orig_post_message => $orig_post_message, attachments => $attach, post_icon => scalar $IN->param('post_icon'), num_attachments => scalar @$attach, can_attach => $can_attach, post_append_signature => $post_append_sig, post_reply_notify => $post_reply_notify, advanced_editor => scalar $IN->param('advanced_editor'), basic_editor => scalar $IN->param('basic_editor'), ($USER ? ( alias_username => scalar $IN->param('alias_username'), ) : ( anonymous => \@anonymous, post_anonymous_email => scalar $IN->param('post_anonymous_email'), guest_username => scalar $IN->param('guest_username') ) ) ); for my $col (keys %$cols) { next if $cols->{$col}->{protect} or exists $page_data{$col} or not defined(my $val = $IN->param($col)); $page_data{$col} = $val; } return($page->{reply_write} => \%page_data); } sub edit { shift; my ($do, $func) = splice @_, 0, 2; my $page = $func->{page}; my $post; my $post_id = $IN->param('post'); # Get the post or print an error page. unless ($post_id and $post = $DB->table('Post' => 'Forum' => 'Category')->select({ post_id => $post_id })->fetchrow_hashref) { return( $page->{no_such_post} => { error => GForum::language('POST_DOES_NOT_EXIST') } ); } require GForum::Forum; GForum::Forum::normalize($post); my $user; if ($post->{user_id_fk}) { $user = $DB->table('User')->get($post->{user_id_fk}); } else { $user = GForum::User::blank_user({ user_username => $post->{post_username}, user_title => \GForum::language('USER_DELETED'), user_signature => $post->{post_signature_deleted} }); } @$post{keys %$user} = values %$user; unless ($USER->{user_forum_permission} >= FORUM_PERM_MODERATOR or ($USER->{user_id} == $post->{user_id_fk} and $post->{forum_allow_user_edit} % 2 # 1 is edit, 3 is edit & delete, but 0 and 2 do not allow editing and (!$post->{forum_edit_timeout} or ($post->{post_time} + $post->{forum_edit_timeout} * 60) > time) ) ) { return GForum::do_func('permission_denied'); } my ($err_code, $error) = shift; $error = sprintf GForum::language($err_code), @_ if $err_code; my $style = $IN->param('forum_style') || $USER->{user_default_post_style} || 3; if ($post->{forum_style} < $style or $post->{forum_style} == 2 and $style == 1) { $style = $post->{forum_style}; } my $post_message; $post_message = $IN->param('post_message') || $post->{post_message}; my $orig_post_message; my %browser = GForum::browser_tags(); my $adv_allowed = ( $browser{is_ie} and $browser{ie_version} >= 5.5 or $browser{is_mozilla} and $browser{mozilla_version} >= 1.4 ); if ($post_message and $IN->param('basic_editor_switch')) { $post_message = GForum::Convert::advanced_editor_convert($post_message); } elsif ( ($IN->param('advanced_editor_switch') or not $IN->param('advanced_editor')) and ( ($post_message and $IN->param('advanced_editor_switch')) or ($IN->param('advanced_editor') and $adv_allowed) or ($USER->{user_advanced_editor} and not $IN->param('basic_editor') and $adv_allowed) ) ) { $orig_post_message = $post_message; _post_message_html(\$post_message, $style >= 2, $post); } # Handle any attachment inline/non-inline changes to post attachments: my (@add_inline_post, @rem_inline_post); for my $k ($IN->param) { if ($k =~ /^att_deinline-(\d+)-post$/ and !$IN->param("att_inline-$1-post")) { push @rem_inline_post, $1 } elsif ($k =~ /^att_inline-(\d+)-post$/ and !$IN->param("att_deinline-$1-post")) { push @add_inline_post, $1 } } if (@add_inline_post or @rem_inline_post) { my $pa = $DB->table('PostAttachment'); $pa->update({ postatt_inline => 1 }, { postatt_id => \@add_inline_post, post_id_fk => $post_id }) if @add_inline_post; $pa->update({ postatt_inline => 0 }, { postatt_id => \@rem_inline_post, post_id_fk => $post_id }) if @rem_inline_post; } my $temp_id; my $attach = []; my $pa = $DB->table('PostAttachment'); $pa->select_options('ORDER BY postatt_id'); my $p_sth = $pa->select({ post_id_fk => $post_id }); while (my $rec = $p_sth->fetchrow_hashref) { for (keys %$rec) { if (s/^post//) { $rec->{$_} = delete $rec->{"post$_"}; } } $rec->{att_type} = "post"; push @$attach, $rec; } my $first_time; if ($temp_id = $IN->param('temp_id')) { my $ta = $DB->table('TempAttachment'); # Handle any attachment inline/non-inline changes to temp (i.e. new) attachments: my (@add_inline_temp, @rem_inline_temp); for my $k ($IN->param) { if ($k =~ /^att_deinline-(\d+)-temp$/ and !$IN->param("att_inline-$1-temp")) { push @rem_inline_temp, $1; } elsif ($k =~ /^att_inline-(\d+)-temp$/ and !$IN->param("att_deinline-$1-temp")) { push @add_inline_temp, $1; } } $ta->update({ tempatt_inline => 1 }, { tempatt_id => \@add_inline_temp, tempatt_msg_id => $temp_id }) if @add_inline_temp; $ta->update({ tempatt_inline => 0 }, { tempatt_id => \@rem_inline_temp, tempatt_msg_id => $temp_id }) if @rem_inline_temp; $ta->select_options('ORDER BY tempatt_id'); my $t_sth = $ta->select({ tempatt_msg_id => $temp_id }); while (my $rec = $t_sth->fetchrow_hashref) { for (keys %$rec) { if (s/^temp//) { $rec->{$_} = delete $rec->{"temp$_"}; } } $rec->{att_type} = "temp"; push @$attach, $rec; } } else { $first_time = 1; $temp_id = generate_temp_id(); } my $can_attach = not cant_attach({ forum_id => $post->{forum_id}, temp_id => $temp_id, post_id => $post_id }); my $append_sig; my $post_reply_notify; if ($first_time) { my $sig = '[' . $CFG->{markup_signature_tag} . ']'; if ($post_message =~ s/\n?\Q$sig\E$//) { $append_sig = 1; } $post_reply_notify = $post->{post_reply_notify}; } else { $append_sig = $IN->param('post_append_signature'); $post_reply_notify = $IN->param('post_reply_notify'); } my $post_icon = $IN->param('post_icon'); $post_icon = $post->{post_icon} if not defined $post_icon; my %page_data = ( temp_id => $temp_id, ($error ? (error => $error) : ()), forum_style_selected => $style, post_subject => $IN->param('post_subject') || $post->{post_subject}, post_message => $post_message, orig_post_message => $orig_post_message, attachments => $attach, num_attachments => scalar @$attach, can_attach => $can_attach, post_append_signature => $append_sig, post_reply_notify => $post_reply_notify, post_icon => $post_icon, advanced_editor => scalar $IN->param('advanced_editor'), basic_editor => scalar $IN->param('basic_editor'), edit_reason => scalar $IN->param('edit_reason') ); my $cols = $DB->table('Post')->cols; for my $col (keys %$cols) { next if $cols->{$col}->{protect} or exists $page_data{$col} or not defined(my $val = $IN->param($col)); $page_data{$col} = $val; } for (keys %$post) { $page_data{$_} = $post->{$_} unless exists $page_data{$_} } for (keys %$user) { $page_data{$_} = $user->{$_} unless exists $page_data{$_} } return($page->{edit} => \%page_data); } sub preview { my $self = shift; my ($do, $func) = @_; my $page = $func->{page}; my $redo = $IN->param('redo') or die 'GForum::Post::Write->preview called with bad arguments - CGI parameter redo not set'; my $post; my $pt = $DB->table('Post'); for (grep exists($pt->{schema}->{cols}->{$_}), $IN->param) { $post->{$_} = $IN->param($_); } $post->{post_time} = time; $post->{post_ip} = $ENV{REMOTE_ADDR}; my $user; if ($redo eq 'post_edit') { my ($uid, $d_username, $d_sig) = $pt->select('user_id_fk', 'post_username', 'post_signature_deleted' => { post_id => scalar $IN->param('post') })->fetchrow; if ($uid) { $user = $DB->table('User')->get($uid); } else { $user = GForum::User::blank_user({ user_username => $d_username, user_title => \GForum::language('USER_DELETED'), user_signature => $d_sig }); } } elsif ($USER) { $user = $USER; } elsif (my $guest_id = $IN->param('anon_id')) { $user = $DB->table('User')->select({ user_id => $guest_id, user_status => ANONYMOUS })->fetchrow_hashref; if ($CFG->{post_guest_custom_username} and my $guest = $IN->param('guest_username')) { $user->{user_username} = $guest; } } @$post{keys %$user} = values %$user if $user; if ($USER and $CFG->{post_user_custom_username} and my $alias = $IN->param('alias_username')) { $post->{post_username} = $alias; } else { $post->{post_username} = $user->{user_username}; } if ($post->{post_message} and $IN->param('advanced_editor')) { $post->{post_message} = GForum::Convert::advanced_editor_convert($post->{post_message}); } $post->{post_message} =~ s/\s+$//; # Remove all trailing whitespace $post->{post_message} .= "\n[$CFG->{markup_signature_tag}]" if $IN->param('post_append_signature'); $post->{_post_preview} = 1; $post->{post_id} ||= $IN->param('post'); $post->{post_unique_id} ||= $IN->param('temp_id'); GForum::Post::normalize($post); $GForum::Template::VARS{preview} = \GForum::Template->parse($page->{preview} => { %$post, preview => 1 }); GForum::do_func($redo); } sub post { shift; my ($do, $func) = @_; uc $ENV{REQUEST_METHOD} eq 'POST' or die "Unable to post with a GET method"; my $page = $func->{page}; my $forum_id = $IN->param('forum'); $forum_id or die "Bad forum ID '$forum_id'"; my $forum = $DB->table('Forum', 'Category')->select({ forum_id => $forum_id })->fetchrow_hashref or die "Bad forum ID '$forum_id'"; my $temp_id = $IN->param('temp_id'); require GForum::Forum; GForum::Forum::normalize($forum); my $post_message = $IN->param('post_message'); if ($IN->param('advanced_editor')) { $post_message = GForum::Convert::advanced_editor_convert($post_message); } $post_message =~ s/\s+$//; # Remove all trailing whitespace $post_message .= "\n[$CFG->{markup_signature_tag}]" if $IN->param('post_append_signature'); my $post_icon = $IN->param('post_icon'); my $good; for (values %{$CFG->{post_icons}}) { $good++, last if $_ eq $post_icon; } $post_icon = undef if not $good; my $post_subject = $IN->param('post_subject'); unless ($post_subject =~ /[^\s\xa0]/) { # \xa0 is Alt-0160 - a non-breaking space,   in HTML if ($CFG->{post_require_subject}) { $GForum::Template::VARS{post_error_no_subject} = 1; return GForum::do_func('post_write'); } else { $post_subject = GForum::language("NO_SUBJECT"); } } my $reply_notify = $IN->param('post_reply_notify') ? 1 : 0; my $sticky = 0; if ($USER and $USER->{user_forum_permission} >= FORUM_PERM_MODERATOR) { $sticky = 1 if $IN->param('post_sticky'); } my $post_style = $IN->param('post_style') || 0; if ($post_style > $forum->{forum_style} or $forum->{forum_style} == 2 and $post_style == 1) { $post_style = $forum->{forum_style}; } my ($user_id, $user_username, $alias_username); if ($USER) { $user_id = $USER->{user_id}; if ($CFG->{post_user_custom_username} and $alias_username = $IN->param('alias_username')) { if (!GForum::Authenticate::auth(valid_username => $alias_username)) { $GForum::Template::VARS{post_error_bad_alias_username} = $GForum::Authenticate::Auth_Error; return GForum::do_func('post_write'); } } $user_username = $USER->{user_username}; } else { unless ($user_id = $IN->param('anon_id') and $DB->table('User')->count({ user_id => $user_id, user_status => ANONYMOUS, user_enabled => 1 })) { $user_id = $DB->table('User')->select(user_id => { user_status => ANONYMOUS, user_enabled => 1 })->fetchrow; } if ($CFG->{post_guest_custom_username} and $alias_username = $IN->param('guest_username')) { if (!GForum::Authenticate::auth('valid_username', $alias_username)) { $GForum::Template::VARS{post_error_bad_guest_username} = $GForum::Authenticate::Auth_Error; return GForum::do_func('post_write'); } } my $u = $DB->table('User')->get($user_id, 'ARRAY', ['user_username']); $user_username = $u->[0] if $u; } $user_id or return($page->{anonymous_not_configured} => { error => GForum::language('POST_ANONYMOUS_DISABLED') }); if (my $pid = $DB->table('Post')->select(post_id => { post_unique_id => $temp_id })->fetchrow) { require GForum::Post::View; my $post = GForum::Post::View::get($pid); return($page->{already_posted} => $post); } my $Post = $DB->table('Post'); my $insert = { user_id_fk => $user_id, post_username => $user_username, (defined $alias_username ? (alias_username => $alias_username) : ()), forum_id_fk => $forum_id, post_unique_id => $temp_id, post_root_id => 0, post_father_id => 0, post_depth => 0, post_time => time, post_subject => $post_subject, post_message => $post_message, post_ip => $ENV{REMOTE_ADDR}, post_last_edit_username => undef, post_last_edit_time => undef, post_anonymous_email => (scalar $IN->param('post_anonymous_email') || undef), post_locked => 0, post_style => $post_style, post_reply_notify => $reply_notify, post_icon => $post_icon, post_sticky => $sticky }; my $cols = $Post->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 $post_id; eval { $post_id = ($Post->insert($insert) or die "$GT::SQL::error\n")->insert_id }; if ($@) { # An error occured while trying to post $GForum::Template::VARS{post_error_other} = $@; return GForum::do_func('post_write'); } my $ta = $DB->table('TempAttachment'); # Handle any attachment inline/non-inline changes: my (@add_inline_temp, @rem_inline_temp); for my $k ($IN->param) { if ($k =~ /^att_deinline-(\d+)-temp$/ and !$IN->param("att_inline-$1-temp")) { push @rem_inline_temp, $1; } elsif ($k =~ /^att_inline-(\d+)-temp$/ and !$IN->param("att_deinline-$1-temp")) { push @add_inline_temp, $1; } } $ta->update({ tempatt_inline => 1 }, { tempatt_id => \@add_inline_temp, tempatt_msg_id => $temp_id }) if @add_inline_temp; $ta->update({ tempatt_inline => 0 }, { tempatt_id => \@rem_inline_temp, tempatt_msg_id => $temp_id }) if @rem_inline_temp; my @attach_errors; my $pa = $DB->table('PostAttachment'); # Get all the temporary attachments associated with this ID so that we can # transfer the attachments from TempAttachment to PostAttachment $ta->select_options('ORDER BY tempatt_id'); my $sth = $ta->select('tempatt_id', { tempatt_msg_id => $temp_id }); while (my $tempatt_id = $sth->fetchrow_array) { $pa->insert({ tempatt_id => $tempatt_id, post_id_fk => $post_id }) or push @attach_errors, delete $pa->{attachment_error}; } my $function = "post_confirm"; # 'post_confirm' isn't actually an option, it's handled here if (not @attach_errors and $USER and exists $CFG->{functions}->{$USER->{user_do_after_post}}) { $function = $USER->{user_do_after_post}; } unless ($function eq "post_confirm" or $function eq "post_confirm_post") { if (substr($function, 0, 4) eq 'post') { $IN->param(post => $post_id); # post actions are going to need the post ID in $IN->param. $HIDDEN{post} = $post_id; } elsif (substr($function, 0, 5) eq 'forum') { $IN->param(forum => $forum_id); $HIDDEN{forum} = $forum_id; } $HIDDEN{do} = $function; my $url = $CFG->{cgi_root_url} . "/gforum.cgi?" . ${GForum::hidden('query')}; print $IN->redirect($url); # If using plugin hooks, setting up a pre hook that prints a header will get around this. return( undef, { %$forum, post_subject => $post_subject, post_message => $post_message, post_id => $post_id, user_username => $USER->{user_username}, user_id => $USER->{user_id}, (@attach_errors ? (attachment_errors => GForum::language('ATTACHMENT_FAILED', join "
\n", @attach_errors)) : ()), } ); } else { return( $page->{post} => { %$forum, post_subject => $post_subject, post_message => $post_message, post_id => $post_id, user_username => $USER->{user_username}, user_id => $USER->{user_id}, (@attach_errors ? (attachment_errors => GForum::language('ATTACHMENT_FAILED', join "
\n", @attach_errors)) : ()), } ); } } sub reply_post { shift; uc $ENV{REQUEST_METHOD} eq 'POST' or die "Unable to post with a GET method"; my ($do, $func) = @_; my $page = $func->{page}; my $parent_id = $IN->param('parent_post_id'); my $parent; my $parent_sth = $DB->table('Post' => 'Forum' => 'Category')->select({ post_id => $parent_id }); unless ($parent_id and $parent = $parent_sth->fetchrow_hashref) { return( $page->{no_such_post} => { error => GForum::language('POST_DOES_NOT_EXIST') } ); } require GForum::Forum; GForum::Forum::normalize($parent); my $forum_id = $parent->{forum_id_fk}; my $temp_id = $IN->param('temp_id'); my $post_icon = $IN->param('post_icon'); my $good; for (values %{$CFG->{post_icons}}) { if ($_ eq $post_icon) { $good = 1; last; } } $post_icon = undef if not $good; my $post_message = $IN->param('post_message'); if ($post_message and $IN->param('advanced_editor')) { $post_message = GForum::Convert::advanced_editor_convert($post_message); } $post_message =~ s/\s+$//; # Remove all trailing whitespace $post_message .= "\n[$CFG->{markup_signature_tag}]" if $IN->param('post_append_signature'); my $post_subject = $IN->param('post_subject'); unless ($post_subject =~ /[^\s\xa0]/) { # \xa0 is Alt-0160 - a non-breaking space,   in HTML if ($CFG->{post_require_subject}) { $GForum::Template::VARS{post_error_no_subject} = 1; return GForum::do_func('post_reply_write'); } else { $post_subject = GForum::language("NO_SUBJECT"); } } my $reply_notify = $IN->param('post_reply_notify') ? 1 : 0; my $root_id = $parent->{post_root_id} || $parent->{post_id}; if ($USER and $USER->{user_forum_permission} < FORUM_PERM_MODERATOR) { # If you have moderator privileges you can post whether ot not the post is locked. my $locked; if ($parent->{post_root_id}) { # The parent isn't the root post $locked = $DB->table('Post')->get($root_id, 'ARRAY', ['post_locked'])->[0]; } else { # If the parent is the root post this saves a select to get the root post $locked = $parent->{post_locked}; } if ($locked) { return($page->{locked}, { error => GForum::language('POST_LOCKED') }); } } my $post_style = $IN->param('post_style') || 0; if ($post_style > $parent->{forum_style} or $parent->{forum_style} == 2 and $post_style == 1) { $post_style = $parent->{forum_style}; } my ($user_id, $user_username, $alias_username); if ($USER) { $user_id = $USER->{user_id}; if ($CFG->{post_user_custom_username} and $alias_username = $IN->param('alias_username')) { if (!GForum::Authenticate::auth(valid_username => $alias_username)) { $GForum::Template::VARS{post_error_bad_alias_username} = $GForum::Authenticate::Auth_Error; return GForum::do_func('post_write'); } } $user_username = $USER->{user_username}; } else { unless ($user_id = $IN->param('anon_id') and $DB->table('User')->count({ user_id => $user_id, user_status => ANONYMOUS, user_enabled => 1 })) { $user_id = $DB->table('User')->select(user_id => { user_status => ANONYMOUS, user_enabled => 1 })->fetchrow; } if ($CFG->{post_guest_custom_username} and $alias_username = $IN->param('guest_username')) { if (!GForum::Authenticate::auth('valid_username', $alias_username)) { $GForum::Template::VARS{post_error_bad_guest_username} = $GForum::Authenticate::Auth_Error; return GForum::do_func('post_reply_write'); } } my $u = $DB->table('User')->get($user_id, 'ARRAY', ['user_username']); $user_username = $u->[0] if $u; } $user_id or return($page->{anonymous_not_configured} => { error => GForum::language('POST_ANONYMOUS_DISABLED') }); if (my $pid = $DB->table('Post')->select(post_id => { post_unique_id => $temp_id })->fetchrow) { require GForum::Post::View; my $post = GForum::Post::View::get($pid); return($page->{already_posted} => $post); } my %data = ( user_id_fk => $user_id, post_username => $user_username, (defined $alias_username ? (alias_username => $alias_username) : ()), forum_id_fk => $forum_id, post_unique_id => $temp_id, post_root_id => $root_id, post_father_id => $parent_id, post_depth => $parent->{post_depth} + 1, post_time => time, post_subject => $post_subject, post_message => $post_message, post_style => $post_style, post_ip => $ENV{REMOTE_ADDR}, post_last_edit_username => undef, post_last_edit_time => undef, post_anonymous_email => (scalar $IN->param('post_anonymous_email')), post_locked => 0, post_reply_notify => $reply_notify, post_icon => $post_icon ); my $Post = $DB->table('Post'); my $cols = $Post->cols; for my $col (keys %$cols) { next if $cols->{$col}->{protect} or exists $data{$col} or not defined(my $val = $IN->param($col)); $data{$col} = $val; } my $post_id = ($DB->table('Post')->insert(\%data) or die $GT::SQL::error)->insert_id; my $ta = $DB->table('TempAttachment'); # Handle any attachment inline/non-inline changes: my (@add_inline_temp, @rem_inline_temp); for my $k ($IN->param) { if ($k =~ /^att_deinline-(\d+)-temp$/ and !$IN->param("att_inline-$1-temp")) { push @rem_inline_temp, $1; } elsif ($k =~ /^att_inline-(\d+)-temp$/ and !$IN->param("att_deinline-$1-temp")) { push @add_inline_temp, $1; } } $ta->update({ tempatt_inline => 1 }, { tempatt_id => \@add_inline_temp, tempatt_msg_id => $temp_id }) if @add_inline_temp; $ta->update({ tempatt_inline => 0 }, { tempatt_id => \@rem_inline_temp, tempatt_msg_id => $temp_id }) if @rem_inline_temp; my @attach_errors; my $pa = $DB->table('PostAttachment'); # Get all the temporary attachments associated with this ID so that we can # transfer the attachments from TempAttachment to PostAttachment $ta->select_options('ORDER BY tempatt_id'); my $sth = $ta->select('tempatt_id', { tempatt_msg_id => $temp_id }); while (my $tempatt_id = $sth->fetchrow_array) { $pa->insert({ tempatt_id => $tempatt_id, post_id_fk => $post_id }) or push @attach_errors, delete $pa->{attachment_error}; } my $notified; if ($parent->{post_reply_notify} and $parent->{user_id_fk} and not ($USER and $USER->{user_id} == $parent->{user_id_fk})) { my ($enabled, $email_addr, $username, $template) = @{$DB->table('User')->get($parent->{user_id_fk}, 'ARRAY', ['user_enabled', 'user_email', 'user_username', 'user_template']) || []}; if ($enabled and $email_addr) { $notified = $parent->{user_id_fk}; my $post = { post_id => $post_id, %data, user_email => $email_addr, user_username => $username }; for (keys %$parent) { # This should add the forum and category columns $post->{$_} = $parent->{$_} unless exists $post->{$_}; $post->{"parent_$_"} = $parent->{$_}; } $post->{post_message_text} = $post->{post_message}; GForum::Post::normalize($post); GForum::Post::plain_text(\$post->{post_message_text}, $post); require GT::Mail::Editor; my $email = GT::Mail::Editor->new(dir => "$CFG->{admin_root_path}/templates", template => ($template or $CFG->{default_template_set} or 'default')); $email->load("reply.eml"); my $headers = $email->headers; my %head; while (my ($k, $v) = each %$headers) { my $val = $v; # Copy it $val = GForum::Template->parse("string", $post, { string => $val }); $head{$k} = $val; } my $body = $email->body; $body = GForum::Template->parse("string", $post, { string => $body }); $CFG->{smtp_server} or $CFG->{mail_path} or die 'No mail path or SMTP server set!'; $head{To} ||= $email_addr; $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 $@; my $sent = eval { $mailer->send }; if (!$sent || $@ and $GForum::DEBUG || $CFG->{debug_level}) { die $@ || $mailer->error; } } } # Handle watched threads: my $condition = GT::SQL::Condition->new(thread_id_fk => '=' => $root_id, tw_last_mail => '<' => \'user_last_seen'); $sth = $DB->table('ThreadWatch', 'User')->select(qw/user_id user_email user_template user_enabled/ => $condition); my (%tplset, @notified); while (my $row = $sth->fetchrow_arrayref) { next if $notified and $notified == $row->[0] # Skip the user if they received a reply notification or !$row->[3]; # or are disabled push @{$tplset{$row->[2]}}, $1 if $row->[0] != $user_id and $row->[1] =~ /([^<>"\s]+\@[\.a-zA-Z0-9-]+)/; push @notified, $row->[0]; } if (keys %tplset) { my $PostUser = $DB->table('Post', 'User'); my $post = $PostUser->select(left_join => { post_id => $post_id })->fetchrow_hashref; { my $root = $PostUser->select(left_join => { post_id => $root_id })->fetchrow_hashref; my $forum = $DB->table('Forum', 'Category')->select({ forum_id => $post->{forum_id_fk} })->fetchrow_hashref; GForum::Forum::normalize($forum); $post->{post_message_text} = $post->{post_message}; GForum::Post::normalize([$root, $post]); GForum::Post::plain_text(\$post->{post_message_text}, $post); for (keys %$root) { $post->{"root_$_"} = $root->{$_}; } for (keys %$forum) { $post->{$_} = $forum->{$_}; } } for my $tpl (keys %tplset) { require GT::Mail::Editor; my $email = GT::Mail::Editor->new(dir => "$CFG->{admin_root_path}/templates", template => ($tpl || $CFG->{default_template_set} || 'default')); $email->load("thread_notify.eml"); my $headers = $email->headers; my %head; while (my ($k, $v) = each %$headers) { my $val = $v; # Copy it $val = GForum::Template->parse("string", $post, { string => $val }); $head{$k} = $val; } my $body = GForum::Template->parse("string", $post, { string => $email->body }); $CFG->{smtp_server} or $CFG->{mail_path} or die 'No mail path or SMTP server set!'; $head{From} ||= $CFG->{admin_email}; $head{Bcc} = join ', ', @{$tplset{$tpl}}; require GT::Mail; my $mailer = GT::Mail->new( %head, msg => $body, ($CFG->{smtp_server} ? (smtp => $CFG->{smtp_server}) : (sendmail => $CFG->{mail_path})) ); local $@; my $sent = eval { $mailer->send }; if (!$sent || $@ and $GForum::DEBUG || $CFG->{debug_level}) { die $@ || $mailer->error; } } $DB->table('ThreadWatch')->update({ tw_last_mail => time }, { user_id_fk => \@notified }); } my $function = "post_confirm"; # 'post_confirm' isn't actually an option, it's handled here if (not @attach_errors and $USER and exists $CFG->{functions}->{$USER->{user_do_after_post}}) { $function = $USER->{user_do_after_post}; } unless ($function eq "post_confirm" or $function eq "post_confirm_post") { if (substr($function, 0, 4) eq 'post') { $IN->param(post => $post_id); # post actions are going to need the post ID in $IN->param. $HIDDEN{post} = $post_id; } elsif (substr($function, 0, 5) eq 'forum') { $IN->param(forum => $forum_id); $HIDDEN{forum} = $forum_id; } $HIDDEN{do} = $function; my $url = $CFG->{cgi_root_url} . "/gforum.cgi?" . ${GForum::hidden('query')}; print $IN->redirect($url); # If using plugin hooks, setting up a pre hook that prints a header will get around this. return; } else { return( $page->{reply_post} => { forum_name => $parent->{forum_name}, forum_id => $parent->{forum_id}, cat_name => $parent->{cat_name}, cat_full_name => $parent->{cat_full_name}, cat_id => $parent->{cat_id}, post_id => $post_id, post_subject => $post_subject, post_message => $post_message, (@attach_errors ? (attachment_errors => GForum::language('ATTACHMENT_FAILED', join "
\n", @attach_errors)) : ()), } ); } } sub edit_post { shift; uc $ENV{REQUEST_METHOD} eq 'POST' or die "Unable to post with a GET method"; my ($do, $func) = @_; my $page = $func->{page}; my $post_id = $IN->param('post') or return GForum::Post->edit('post_edit', $CFG->{functions}->{post_edit}, 'POST_BAD_POST'); my $post = $DB->table('Post' => 'Forum' => 'Category')->select({ post_id => $post_id })->fetchrow_hashref or return GForum::Post->edit('post_edit', $CFG->{functions}->{post_edit}, 'POST_BAD_POST'); require GForum::Forum; GForum::Forum::normalize($post); my $post_icon = $IN->param('post_icon'); my $good; for (values %{$CFG->{post_icons}}) { $good++, last if $_ eq $post_icon; } $post_icon = undef if not $good; my $post_message = $IN->param('post_message'); if ($post_message and $IN->param('advanced_editor')) { $post_message = GForum::Convert::advanced_editor_convert($post_message); } $post_message =~ s/\s+$//; # Remove all trailing whitespace $post_message .= "\n[$CFG->{markup_signature_tag}]" if $IN->param('post_append_signature'); my $post_subject = $IN->param('post_subject'); unless ($post_subject =~ /[^\s\xa0]/) { # \xa0 is Alt-0160 - a non-breaking space,   in HTML if ($CFG->{post_require_subject}) { $GForum::Template::VARS{post_error_no_subject} = 1; return GForum::do_func('post_write'); } else { $post_subject = GForum::language("NO_SUBJECT"); } } unless ($USER->{user_forum_permission} >= FORUM_PERM_MODERATOR or ($USER->{user_id} == $post->{user_id_fk} and $post->{forum_allow_user_edit} % 2 # 1 is edit, 3 is edit & delete, but 0 and 2 do not allow editing and (!$post->{forum_edit_timeout} or ($post->{post_time} + $post->{forum_edit_timeout} * 60) > time) ) ) { $GForum::Template::VARS{permission_denied_reason} = GForum::language('POST_EDIT_TIME_EXPIRED'); return GForum::do_func('permission_denied'); } my $edit_time = time; my $post_style = $IN->param('post_style'); if ($post_style > $post->{forum_style} or $post->{forum_style} == 2 and $post_style == 1) { $post_style = $post->{forum_style}; } my $post_reply_notify = $IN->param('post_reply_notify') && 1 || undef; my %data = ( post_subject => $post_subject, post_message => $post_message, post_icon => $post_icon, (defined $post_style ? (post_style => $post_style) : ()), post_last_edit_username => $USER->{user_username}, post_last_edit_time => $edit_time, post_reply_notify => $post_reply_notify ); my $Post = $DB->table('Post'); my $cols = $Post->cols; for my $col (keys %$cols) { next if $cols->{$col}->{protect} or exists $data{$col} or not defined(my $val = $IN->param($col)); $data{$col} = $val; } $DB->table('Post')->update( \%data, { post_id => $post->{post_id} } ) or die "Unable to update record: $GT::SQL::error"; # Reselect the post to get the updates (in case a subclass changed more than what the update contained): $post = $DB->table('Post' => 'Forum' => 'Category')->select({ post_id => $post_id })->fetchrow_hashref; require GForum::Forum; GForum::Forum::normalize($post); $DB->table('EditLog')->insert({ post_id_fk => $post->{post_id}, user_id_fk => $USER->{user_id}, edit_time => $edit_time, edit_reason => scalar($IN->param('edit_reason')) || '' }); my $temp_id = $IN->param('temp_id'); my $ta = $DB->table('TempAttachment'); my $pa = $DB->table('PostAttachment'); # Handle any attachment inline/non-inline changes: my (@add_inline_post, @rem_inline_post, @add_inline_temp, @rem_inline_temp); for my $k ($IN->param) { if ($k =~ /^att_deinline-(\d+)-(temp|post)$/ and !$IN->param("att_inline-$1-$2")) { if ($2 eq 'post') { push @rem_inline_post, $1 } else { push @rem_inline_temp, $1 } } elsif ($k =~ /^att_inline-(\d+)-(temp|post)$/ and !$IN->param("att_deinline-$1-$2")) { if ($2 eq 'post') { push @add_inline_post, $1 } else { push @add_inline_temp, $1 } } } $pa->update({ postatt_inline => 1 }, { postatt_id => \@add_inline_post, post_id_fk => $post_id }) if @add_inline_post; $pa->update({ postatt_inline => 0 }, { postatt_id => \@rem_inline_post, post_id_fk => $post_id }) if @rem_inline_post; $ta->update({ tempatt_inline => 1 }, { tempatt_id => \@add_inline_temp, tempatt_msg_id => $temp_id }) if @add_inline_temp; $ta->update({ tempatt_inline => 0 }, { tempatt_id => \@rem_inline_temp, tempatt_msg_id => $temp_id }) if @rem_inline_temp; my @attach_errors; # Get all the temporary attachments that we added to this post so that we # can transfer the attachments from TempAttachment to PostAttachment $ta->select_options('ORDER BY tempatt_id'); my $sth = $ta->select('tempatt_id', { tempatt_msg_id => $temp_id }); while (my $tempatt_id = $sth->fetchrow_array) { $pa->insert({ tempatt_id => $tempatt_id, post_id_fk => $post_id }) or push @attach_errors, delete $pa->{attachment_error}; } my $function = "post_confirm"; # 'post_confirm' isn't actually an option, it's handled here if (not @attach_errors and $USER and exists $CFG->{functions}->{$USER->{user_do_after_post}}) { $function = $USER->{user_do_after_post}; } unless ($function eq "post_confirm" or $function eq "post_confirm_post") { if (substr($function, 0, 4) eq 'post') { $IN->param(post => $post_id); # post actions are going to need the post ID in $IN->param. $HIDDEN{post} = $post_id; } elsif (substr($function, 0, 5) eq 'forum') { $IN->param(forum => $post->{forum_id_fk}); $HIDDEN{forum} = $post->{forum_id_fk}; } $HIDDEN{do} = $function; my $url = $CFG->{cgi_root_url} . "/gforum.cgi?" . ${GForum::hidden('query')}; print $IN->redirect($url); # If using plugin hooks, setting up a pre hook that prints a header will get around this. return; } else { return( $page->{edit_post} => $post ); } } # Converts a scalar reference into it's HTML equivelant. Used when switching to # the advanced editor. Converts markup into HTML. Note, however, that this # differs in one way: URL's, which markup converts to: gforum.cgi?url=... do not # forward through gforum.cgi and are kept as the original URL. The third # argument, $post, is needed when handling [inline] image tags; specifically # the hashref must contain at least post_id, but possibly also both # '_post_preview' and 'post_unique_id' values. sub _post_message_html { my ($message, $html, $post) = @_; GForum::Convert::escape_html($$message) unless $html; my $save = $GForum::Convert::Leave_Dot; $GForum::Convert::Leave_Dot = 1; my $inline_opts = [ $post->{post_id}, \my $forum_inline_calced, \my %forum_inline, [$post->{forum_id_fk} || ()], $post->{forum_id_fk} || undef, $post->{_post_preview} ? (1, $post->{post_unique_id}) : () ]; GForum::Convert::convert_markup($message, \&GForum::Post::_inline, $inline_opts); $GForum::Convert::Leave_Dot = $save; # Convert the URL's: has to become . Also, the .... has to be url unescaped. $$message =~ s//qq||/eg; $$message =~ 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 conversion down quite a bit. $$message =~ s/^( +)/' ' x length $1/gem; $message; } # Takes one argument - a hashref consisting of two or three keys - 'forum_id', # 'post_id' (only required for edit mode), and 'temp_id'. # The returns true if you can't add attachments to that post for a variety of # reasons. The value returned is actually the reason that attachments can't be # attached to the post (or a new post of the forum). sub cant_attach { my @args = @_; GT::Plugins->dispatch($CFG->{admin_root_path} . '/Plugins/GForum', 'post_cant_attach', sub { return _plg_cant_attach(@args) }); } sub _plg_cant_attach { $Attachment_Max = undef; my $args = shift; my ($forum_id, $temp_id, $post_id) = @$args{qw/forum_id temp_id post_id/}; my $forum = $DB->table('Forum')->get($forum_id) or die "No such forum ID '$forum_id'"; $USER or $forum->{forum_allow_guest_attachments} or return GForum::language('ATTACHMENTS_NOT_ALLOWED-GUESTS'); if (!$forum->{forum_allow_attachments}) { return GForum::language('ATTACHMENTS_NOT_ALLOWED'); } if ($forum->{forum_attachments}) { # If this is 0 it means unlimited attachments are allowed per post my $count = $DB->table('TempAttachment')->count({ tempatt_msg_id => $temp_id }); # If this is an edit, we need to add the attachments already posted to the count if ($post_id) { $count += $DB->table('PostAttachment')->count({ post_id_fk => $post_id }); } if ($count >= $forum->{forum_attachments}) { return GForum::language('ATTACHMENT_COUNT_EXCEEDED'); } } if ($CFG->{post_attachments_max_size}) { my $total_size = $DB->table('PostAttachment')->_attachments_size; if ($total_size >= $CFG->{post_attachments_max_size}) { return GForum::language('ATTACHMENT_LIMIT_EXCEEDED'); } $Attachment_Max = $CFG->{post_attachments_max_size} - $total_size; } if ($forum->{forum_attachment_max_size}) { if (not defined $Attachment_Max or $Attachment_Max > $forum->{forum_attachment_max_size}) { $Attachment_Max = $forum->{forum_attachment_max_size}; } } if ($CFG->{post_attachments_max_count}) { my $total_count = $DB->table('PostAttachment')->count() + $DB->table('TempAttachment')->count({ tempatt_type => 'Post' }); if ($total_count > $CFG->{post_attachments_max_count}) { return GForum::language('ATTACHMENT_COUNT_EXCEEDED'); } } return; } sub generate_temp_id { require GT::MD5; my $id = GT::MD5::md5_hex(time . $$ . rand(16000)); while ($DB->table('Post')->count(post_unique_id => $id) > 0) { $id = GT::MD5::md5_hex(time . $$ . rand(16000)); } return $id; } 1;