# ==================================================================
# Gossamer Forum - Advanced web community
#
# Website : http://gossamer-threads.com/
# Support : http://gossamer-threads.com/scripts/support/
# Revision : $Id: MassMailer.pm,v 1.8 2005/09/19 19:44:26 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.
# ==================================================================
package GForum::MassMailer;
# ==================================================================
# This package contains some builtin functions useful in your templates.
#
use GForum qw/$DB $IN $CFG/;
use GT::Mail::BulkMail qw/$VALID_HOST/;
use GT::CGI;
use strict;
use vars qw(%ACTIONS $NEW_TEMPLATE @MONTH @DAY @WEEKDAY);
$NEW_TEMPLATE = '(New template)';
@MONTH = qw/January February March April May June July August September October November December/;
@DAY = qw/blank 1st 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 11th 12th 13th 14th 15th 16th 17th 18th 19th 20th 21st 22nd 23rd 24th 25th 26th 27th 28th 29th 30th 31st/;
@WEEKDAY = qw/Sunday Monday Tuesday Wednesday Thursday Friday Saturday/;
# (See _save_template for arguments)
sub add_template ($$$$$$;$) {
_save_template(@_);
}
# (See _save_template for arguments)
sub save_template ($$$$$$;$) {
_save_template(@_);
}
# Deletes a template based on its name
sub del_template ($) {
$DB->table('EmailTemplate')->delete(shift);
}
# Updates (or creates) a row for the template given in EmailTemplate
# Takes up to 6 args:
# name, from, fromname, subject, message, message format ('text' or 'html'),
# link template (for newsletter template)
sub _save_template {
my ($name,$from,$fromname,$subject,$message,$format) = @_;
for ($name,$from,$fromname,$subject,$message) {
defined $_ or $_ = "";
}
$format = 'text' unless defined $format and $format eq 'html';
my $table = $DB->table('EmailTemplate');
if ($table->count({ email_tpl_name => $name })) {
$table->update(
{
email_tpl_from => $from,
email_tpl_from_name => $fromname,
email_tpl_subject => $subject,
email_tpl_body => $message,
email_tpl_format => $format
},
{
email_tpl_name => $name
}
);
}
else {
$table->insert(
{
email_tpl_name => $name,
email_tpl_from => $from,
email_tpl_from_name => $fromname,
email_tpl_subject => $subject,
email_tpl_body => $message,
email_tpl_format => $format
}
);
}
}
# Returns a template with the name given by the provided argument.
# Returns a 5 element list of: from, fromname, subject, message, message format ('text' or 'html')
sub get_template ($) {
return @{$DB->table('EmailTemplate')->get(shift, 'ARRAY') or [('') x 5, 'text']}[1..5];
}
sub template_names () {
my @return = map $_->[0], @{$DB->table('EmailTemplate')->select('email_tpl_name')->fetchall_arrayref};
@return;
}
# Returns an HTML option string ("...") based on the provided arguments.
# Takes 1 or 2 arguments:
# - an array reference of options
# - a "selected" option. Any matching option will be given a "selected" tag.
sub make_opts ($;$) {
my $opts = shift;
my $selected = shift || "";
return join "\n", map {
my $escaped = GT::CGI::html_escape($_) || '';
qq||
} @$opts;
}
# Returns a string such as "Saturday, January 1st, 2000, 00:00:00" for a integral time such as 946713600
sub make_date_string ($) {
my $date = shift;
my @lt = localtime($date);
return "$WEEKDAY[$lt[6]], $MONTH[$lt[4]] $DAY[$lt[3]], ".
($lt[5]+1900).", ".sprintf("%02d:%02d:%02d",@lt[2,1,0]);
}
# =========================================
# Actions
# =========================================
#
# These subroutines (in the GForum::MassMailer::ACTIONS namespace) are called directly when a CGI
# option of: action=option is made.
#
# The default frames page
sub GForum::MassMailer::ACTIONS::frames {
GForum::page(
"email_frames.html",
{
version => $CFG->{version},
main => "admin.cgi?action=main",
contents => "admin.cgi?action=contents"
}
);
}
# A generic error page
sub GForum::MassMailer::ACTIONS::error {
GForum::page(
"email_error.html",
{
error => "@_"
}
);
}
# The main body page (to be displayed by GForum::MassMailer::ACTIONS::frames)
sub GForum::MassMailer::ACTIONS::main {
GForum::page(
"email_default.html",
{ }
);
}
# The contents page (to be displayed by GForum::MassMailer::ACTIONS::frames)
sub GForum::MassMailer::ACTIONS::contents {
GForum::page(
"email_contents.html",
{ }
);
}
# * -> "Load" (template)
sub GForum::MassMailer::ACTIONS::Load {
my $name = $IN->param('name');
$GForum::MassMailer::ACTIONS::{$IN->param('previous')}->($name,get_template($name))
if exists $GForum::MassMailer::ACTIONS::{$IN->param('previous')} and ref *{$GForum::MassMailer::ACTIONS::{$IN->param('previous')}}{CODE} eq 'CODE';
}
# * -> "Save" (template)
sub GForum::MassMailer::ACTIONS::Save {
my $name = $IN->param('name');
return $GForum::MassMailer::ACTIONS::{SaveAs}->() if $name eq $NEW_TEMPLATE;
my $from = $IN->param('from');
my $fromname = $IN->param('fromname');
my $subject = $IN->param('subject');
my $message = $IN->param('message');
my $format = $IN->param('messageformat');
save_template($name,$from,$fromname,$subject,$message,$format);
$GForum::MassMailer::ACTIONS::{$IN->param('previous')}->($name,(get_template($name))[0..4],"Template saved successfully")
if exists $GForum::MassMailer::ACTIONS::{$IN->param('previous')} and ref *{$GForum::MassMailer::ACTIONS::{$IN->param('previous')}}{CODE} eq 'CODE';
}
# * -> "Save as..." (template)
sub GForum::MassMailer::ACTIONS::SaveAs {
$IN->delete('name');
my %substitutions = (
notes => "@_",
from => defined $IN->param('from') ? scalar $IN->param('from') : "",
fromname => defined $IN->param('fromname') ? scalar $IN->param('fromname') : "",
subject => defined $IN->param('subject') ? scalar $IN->param('subject') : "",
message => defined $IN->param('message') ? scalar $IN->param('message') : "",
messageformat => defined $IN->param('messageformat') ? scalar $IN->param('messageformat') : "text",
previous => defined $IN->param('previous') ? scalar $IN->param('previous') : "",
hidden_fields => ""
);
$IN->delete('from');
$IN->delete('fromname');
$IN->delete('subject');
$IN->delete('message');
$IN->delete('messageformat');
$IN->delete('action');
chomp($substitutions{from});
if ($substitutions{from} !~ /^[\x21-\x7e]+\@$VALID_HOST(?!\n)$/) {
$GForum::MassMailer::ACTIONS::{$IN->param('previous')}->(undef,"",@substitutions{qw/fromname subject message messageformat/},"Invalid e-mail address entered. Correct it before saving the template")
if exists $GForum::MassMailer::ACTIONS::{$IN->param('previous')} and ref *{$GForum::MassMailer::ACTIONS::{$IN->param('previous')}}{CODE} eq 'CODE';
return;
}
if ($IN->param('previous') and substr($IN->param('previous'),0,8) eq 'selected') {
$substitutions{hidden_fields} = join "\n", map '', $IN->param;
}
for (keys %substitutions) {
next if $_ eq 'hidden_fields';
$substitutions{$_} =~ s/&/&/g;
$substitutions{$_} =~ s/"/"/g;
$substitutions{$_} =~ s/>/>/g;
$substitutions{$_} =~ s/</g;
}
GForum::page(
"email_newtemp_save_as.html",
\%substitutions
);
}
# * -> (Template) "Save as..." or "Save" with "(New template)" selected -> "Add Template"
sub GForum::MassMailer::ACTIONS::email_newtemp {
my $new_name = $IN->param('name');
my $previous = $IN->param('previous');
$new_name =~ s/^\s+//;
$new_name =~ s/\s+$//;
if ($new_name !~ /\S/) {
GForum::MassMailer::ACTIONS::SaveAs(qq|Bad input: Invalid template name ($new_name)!|);
}
else {
my $from = $IN->param('from');
chomp($from);
add_template($new_name,($from =~ /^[\x20-\x7e]+\@$VALID_HOST$/ ? $from : ''),
$IN->param('fromname'),$IN->param('subject'),$IN->param('message'),$IN->param('messageformat'));
$GForum::MassMailer::ACTIONS::{$previous}->($new_name,(get_template($new_name))[0..4],"Template saved successfully");
}
}
# * -> "Delete" (template)
sub GForum::MassMailer::ACTIONS::Delete {
del_template($IN->param('name')) if $IN->param('name') and $IN->param('name') ne $NEW_TEMPLATE;
$GForum::MassMailer::ACTIONS::{$IN->param('previous')}->() if exists $GForum::MassMailer::ACTIONS::{$IN->param('previous')} and ref *{$GForum::MassMailer::ACTIONS::{$IN->param('previous')}}{CODE} eq 'CODE';
}
# "All Users" -> "Send"
sub GForum::MassMailer::ACTIONS::Send {
my $to = $IN->param('emailsto');
return unless $to and $to eq 'EVERYONE';
unless ($IN->param('from') and $IN->param('from') =~ /^[\x21-\x7e]+\@$VALID_HOST(?!\n)$/) {
my %substitutions = (
notes => "@_",
from => defined $IN->param('from') ? scalar $IN->param('from') : "",
fromname => defined $IN->param('fromname') ? scalar $IN->param('fromname') : "",
subject => defined $IN->param('subject') ? scalar $IN->param('subject') : "",
message => defined $IN->param('message') ? scalar $IN->param('message') : "",
messageformat => defined $IN->param('messageformat') ? scalar $IN->param('messageformat') : "text",
previous => defined $IN->param('previous') ? scalar $IN->param('previous') : "",
hidden_fields => ""
);
$IN->delete('from');
$IN->delete('fromname');
$IN->delete('subject');
$IN->delete('message');
$IN->delete('messageformat');
$IN->delete('action');
$GForum::MassMailer::ACTIONS::{$IN->param('previous')}->(undef,"",@substitutions{qw/fromname subject message messageformat/},"Invalid from e-mail address entered. You must correct it before sending the e-mails")
if exists $GForum::MassMailer::ACTIONS::{$IN->param('previous')} and ref *{$GForum::MassMailer::ACTIONS::{$IN->param('previous')}}{CODE} eq 'CODE';
return;
}
my $sth = $DB->table('User')->select('user_id');
my $mailingnum = $DB->table('MailingIndex')->insert({
mailing_from => $IN->param('from'),
mailing_name => $IN->param('fromname'),
mailing_subject => $IN->param('subject'),
mailing_message => $IN->param('message'),
mailing_format => $IN->param('messageformat'),
})->insert_id;
my $emailtable = $DB->table('EmailRecipient');
while (my $uid = $sth->fetchrow_arrayref) {
$emailtable->insert({
mailing_id_fk => $mailingnum,
user_id_fk => $uid->[0],
recipient_sent => 0
});
}
$GForum::MassMailer::ACTIONS::{mailings}->('Mailing queued for sending. To send, select "Start mailing" below beside the mailing you just queued.');
}
# * -> "x recipients"
sub GForum::MassMailer::ACTIONS::list_addresses {
my $to = $IN->param('emailsto');
return unless defined $to;
if ($to eq 'EVERYONE') {
GForum::page(
"email_list.html",
{
addresses => join("
\n", $DB->table('User')->select('user_email')->fetchall_list)
}
);
}
elsif ($to eq 'SELECTEDUSERS') {
my $table = $DB->table('User');
$IN->delete("action");
my $sth = $table->query_sth($IN);
my @emails;
while ($_ = $sth->fetchrow_hashref) {
push @emails, $_->{user_email} if $_->{user_email};
}
GForum::page(
"email_list.html",
{
addresses => join("
\n", @emails)
}
);
}
else {
# It's just a mailing ID that has been passed
my @emails;
my $sth = $DB->table('EmailRecipient', 'User')->select(user_email => { mailing_id_fk => $to });
while ($_ = $sth->fetchrow_arrayref) {
push @emails, $_->[0] if $_->[0];
}
GForum::page(
"email_list.html",
{
addresses => join("
\n", @emails)
}
);
}
}
# "All Users"
sub GForum::MassMailer::ACTIONS::email_everyone {
my ($selected,$from,$fromname,$subject,$message,$format,$error) = splice @_,0,7;
GForum::page(
"email_everyone.html",
{
number => $DB->table('User')->count(),
templates => make_opts([$NEW_TEMPLATE,template_names()],$selected),
from => GT::CGI::html_escape($from) || '',
fromname => GT::CGI::html_escape($fromname) || '',
subject => GT::CGI::html_escape($subject) || '',
message => GT::CGI::html_escape($message) || '',
messageformat => make_opts([qw/text html/],$format),
error => $error || ""
}
);
}
# "Selected Users"
sub GForum::MassMailer::ACTIONS::selected_users {
$IN->param('do' => 'massmailer_search_selected_users'); # having a do with a value containing "search" will hide the user_do_after_post field, which will screw up searches.
my $html = $DB->html($DB->table('User'), $IN);
$IN->delete("do");
$html->{code}{ReceiveMail} = sub { qq{