Apache-App-Mercury

 view release on metacpan or  search on metacpan

Mercury.pm  view on Meta::CPAN

	if ($q->param('add_box')) {
	    if ($self->verify_new_mailbox($q->param('new_box'))) {
		$self->add_new_mailbox($q->param('new_box'));
		$self->checkmail;
		$q->delete('new_box');
	    }
	} elsif ($q->param('delete_box')) {
	    $self->delete_mailbox($q->param('custom_box'),
				  $q->param('delete_mail_in_box'));
	    $self->checkmail;
	    $q->delete('custom_box');
	    $q->delete('delete_mail_in_box');
	} elsif ($q->param('commit_filter')) {
	    $self->edit_filters;
	    $self->checkmail;
#	    $q->delete('trans_filter');
	} elsif ($q->param('update_auto_forward')) {
	    $self->update_auto_forward;
	    $self->checkmail;
	}
	$self->{'state'} = 'edit_settings';
	$self->show_mail_settings;
	$controller->sitemark('/messaging.settings');

    } elsif ($self->{'state'} eq 'compose_message') {

	$self->save_compose_message_fields;
	$controller->sitemark('/messaging.compose');

	$controller->infomsg("You must take action on your existing composition before creating a transaction-related message.")
	  if ($q->param('reply_trans') or $q->param('compose_trans'));

	if ($q->param('preview')) {
	    my ($fail, $recip, $recip_desc) =
	      $self->verify_recipient($self->{compose_msg}->{'sent_to'}, 1);
	    unless ($fail) {
		$self->{compose_msg}->{'sent_to'} = $recip;
		$self->{compose_msg}->{'recipient_desc'} = $recip_desc;

		$self->{'state'} = 'preview_message';
		$self->show_mail_preview;
		$controller->sitemark('/messaging.preview');
		return;
	    }
	} elsif ($q->param('return')) {
	    $controller->infomsg("Your composition has been saved in memory.  It will be removed when you log out.");
	    $self->{'state'} = 'message_center';
	    $self->show_mail_center;
	    $controller->sitemark('/messaging');
	    return;
	} elsif ($q->param('reset')) {
	    $self->reset_compose_message;
	} elsif ($q->param('change_recip')) {
	    $self->{compose_msg}->{'action'} .= "-changed_recip";
	} elsif ($q->param('memo')) {
	    $self->{compose_msg}->{'sent_to'} = $self->{user_manager}->userprofile('user');
	    $self->{compose_msg}->{'recipient_desc'} = $self->{user_manager}->userprofile('user_desc');
	} elsif ($q->param('nonmemo')) {
	    $self->{compose_msg}->{'sent_to'} = '';
	    $self->{compose_msg}->{'recipient_desc'} = '';
	} elsif (defined (my $attach_no = $q->param('remove_attach'))) {
	    splice(@{$self->{compose_msg}->{'Attachments'}}, $attach_no, 1);
	}

	$self->show_mail_compose;

    } elsif ($self->{'state'} eq 'preview_message') {

	$self->save_compose_message_fields;
	$controller->sitemark('/messaging.preview');

	$controller->infomsg("You must take action on your existing composition before creating a transaction-related message.")
	  if ($q->param('reply_trans') or $q->param('compose_trans'));

	if ($q->param('send')) {
	    $self->{'state'} = 'message_center';
	    $self->message_send;
	    $self->check_mail;
	    $self->show_mail_center;
	    $controller->sitemark('/messaging');
	} elsif ($q->param('make_changes')) {
	    $self->{'state'} = 'compose_message';
	    $self->show_mail_compose;
	    $controller->sitemark('/messaging.compose');
	} elsif ($q->param('return')) {
	    $controller->infomsg("Your composition has been saved in memory.  It will be removed when you log out.");
	    $self->{'state'} = 'message_center';
	    $self->show_mail_center;
	    $controller->sitemark('/messaging');
	} else {
	    $self->show_mail_preview;
	}

    } elsif ($q->param('compose') or $q->param('compose_trans')) {

	if (ref $self->{compose_msg} ne "Apache::App::Mercury::Message") {
	    $self->reset_compose_message;
	    $self->{compose_msg}->{'transcode'} = $q->param('transcode')
	      if $q->param('compose_trans');
	} elsif ($q->param('compose_trans')) {
	    $controller->infomsg("You must take action on your saved composition before creating a new transaction-related message.");
	}

	$self->{'state'} = 'compose_message';
	$self->show_mail_compose;
	$controller->sitemark('/messaging.compose');

    } elsif ($args{'mailto'}) {

	if (ref $self->{compose_msg} ne "Apache::App::Mercury::Message") {
	    $self->reset_compose_message;
	    my ($fail, $recip, $recip_desc) =
	      $self->verify_recipient($args{'mailto'}, 1);
	    unless ($fail) {
		$self->{compose_msg}->{'action'} = 'mailto';
		$self->{compose_msg}->{'sent_to'} = $recip;
		$self->{compose_msg}->{'recipient_desc'} = $recip_desc;
	    }
	} else {
	    $controller->infomsg("You must take action on your saved composition before creating a new message.");
	}

Mercury.pm  view on Meta::CPAN


    return 1;
}

sub sort_mailbox {
    my ($self, $box) = @_;
    my $q = $self->{q};

    $box = $self->{'current_box'} if !$box;

    my $sortby = $self->{$box}->{'sortby'};
    my $sortdir = $self->{$box}->{'sortdir'};
    my $index = $self->{$box}->{'index'};

    if ($sortdir eq 'down') { # sort descendingly
	$index = [ sort { uc($self->{$box}->{'msgs'}->{$b}->{$sortby}) cmp uc($self->{$box}->{'msgs'}->{$a}->{$sortby}) } @$index ];
    } else { # sort ascendingly
	$index = [ sort { uc($self->{$box}->{'msgs'}->{$a}->{$sortby}) cmp uc($self->{$box}->{'msgs'}->{$b}->{$sortby}) } @$index ];
    }
    $self->{$box}->{'index'} = $index;
}

sub make_read {
    my ($self) = @_;
    my $q = $self->{q};

    my $box = $self->{'current_box'};
    my $msg = $self->{$box}->{'index'}->[$self->{'cur_index'}];

    if ($box ne 'outbox' and
	$self->{$box}->{'msgs'}->{$msg}->{'status'} eq 'unread') {
	if ($self->change_status(undef, 'read', undef, $msg)) {
	    $self->check_mail;
	}
    }
}

sub retrieve_message {
    my ($self, $id) = @_;
    my $msgs = $self->{$self->{'current_box'}}->{'msgs'};

    return undef unless defined $id;

    # retrieve it from memory if its easily accessible
    return $msgs->{$id} if ref $msgs->{$id} eq "Apache::App::Mercury::Message";

    # otherwise get out of table (for transactions)
    return $self->get_messages(undef, undef, [ $id ])->{$id};
}

sub save_compose_message_fields {
    my ($self) = @_;
    my $q = $self->{q};

    $self->{compose_msg}->{'sent_to'} = $q->param('recipient')
      if defined $q->param('recipient');
    $self->{compose_msg}->{'subject'} = $q->param('subject')
      if defined $q->param('subject');
    $self->{compose_msg}->{'body'} = $q->param('body')
      if defined $q->param('body');
    $self->{compose_msg}->{'num_to_attach'} =
      $q->param('num_files_to_attach')
	if defined $q->param('num_files_to_attach');
    $self->{compose_msg}->{'security'} = $q->param('security')
      if defined $q->param('security');
}

sub reset_compose_message {
    my ($self) = @_;
    my $q = $self->{q};
    $self->{compose_msg} = Apache::App::Mercury::Message->new
      ({ 'sender' => $self->{user_manager}->userprofile('user') });
    $self->{compose_msg}->initialize($self);

    $self->{compose_msg}->{'action'} = 'new';
    $self->{compose_msg}->{'subject'} = '';
    $self->{compose_msg}->{'sent_to'} = '';
    $self->{compose_msg}->{'recipient_desc'} = '';
    $self->{compose_msg}->{'transcode'} = '';
    $self->{compose_msg}->{'body'} = '';
    delete $self->{compose_msg}->{'Attachments'};
}

sub set_compose_reply {
    my ($self, $origmsg) = @_;
    my $new = $self->{compose_msg};

    my ($fail, $recip, $recip_desc) =
      $self->verify_recipient($origmsg->{'sender'}, 1);
    return 0 if $fail;

    $new->{'action'} = 'reply';
    $new->{'subject'} = "Re: ".$origmsg->{'subject'};
    $new->{'sent_to'} = $recip;
    $new->{'recipient_desc'} = $recip_desc;
    $new->{'transcode'} = $origmsg->{'transcode'};
    $new->{'body'} = $origmsg->{'sender'}." wrote:\n\n".$origmsg->{'body'};
    $new->{'body'} =~ s/^/> /gm;
    $new->{'body'} = "\n\n\n".$new->{'body'};
    $new->{'security'} = $origmsg->{'security'};
    $new->{'security_fixed'} = 1 if $origmsg->{'security_fixed'};
    $new->{'Attachments'} = dclone $origmsg->{'Attachments'}
      if ref $origmsg->{'Attachments'} eq "ARRAY";

    return 1;
}

sub set_compose_forward {
    my ($self, $origmsg) = @_;
    my $new = $self->{compose_msg};

    $new->{'action'} = 'forward';
    $new->{'subject'} = "Fwd: ".$origmsg->{'subject'};
    $new->{'sent_to'} = '';
    $new->{'recipient_desc'} = '';
    $new->{'transcode'} = $origmsg->{'transcode'};
    $new->{'body'} = $origmsg->{'sender'}." wrote:\n\n".$origmsg->{'body'};
    $new->{'body'} =~ s/^/> /gm;
    $new->{'body'} = "\n\n\n".$new->{'body'};
    $new->{'security'} = $origmsg->{'security'};
    $new->{'security_fixed'} = 1 if $origmsg->{'security_fixed'};
    $new->{'Attachments'} = dclone $origmsg->{'Attachments'}
      if ref $origmsg->{'Attachments'} eq "ARRAY";

Mercury.pm  view on Meta::CPAN



sub verify_recipient {
    my ($self, $recip, $show_fail_message) = @_;
    my $q = $self->{q};
    my $controller = $self->{controller};

    # remove all whitespace (user_names can't have any)
    $recip =~ s/\s//g;

    $self->warn("->verify_recipient: checking '$recip'.");
    if (!$recip) {
	$controller->infomsg("You must enter a recipient.") if $show_fail_message;
	return ('fail', undef, undef);
    } elsif ($recip eq $self->{user_manager}->userprofile('user')) {
	return (0, $self->{user_manager}->userprofile('user'),
		"(".$self->{user_manager}->userprofile('user_desc').")");
    } else {
	my @recps = split(';', $recip);
	my @chk_recip = $self->{user_manager}->get_userinfo(@recps);
	my ($usrs, $descript);
	unless (@chk_recip) {
	    $controller->infomsg("Unknown user id: " . $recip)
	      if $show_fail_message;
	    return ('fail', undef, undef);
	}
	my $dispclass = Apache::App::Mercury::Config::DISPLAY_CLASS();
	foreach (@chk_recip) {
	    $usrs .= ($usrs ? ';' : '') . $_->{'user'};
	    $descript .=
	      (($descript ? '; ' : '') .
	       ($dispclass->can("USER_INFO_HREF")
		? $dispclass->USER_INFO_HREF($_->{'user'}, $q)
		: '') .
	       " (" . $_->{'fname'}." ".$_->{'lname'} . ")");
	}
	$controller->infomsg("Not all user ids were valid.  You may wish to ".$q->em("make changes")." and try again.")
	  if ($show_fail_message and $#recps != $#chk_recip);
	return (0, $usrs, $descript);
    }
}

sub cancel_operation {
    my ($self) = @_;
    my $q = $self->{q};

    $self->{controller}->infomsg("The previous operation has been cancelled.");

    # delete appropriate data and params
    $q->delete('cancel');
    delete $self->{compose_msg};
}

sub message_send {
    my ($self) = @_;
    my $q = $self->{q};
    my $compose = $self->{compose_msg};

    my $is_memo = ($compose->{'sender'} eq $compose->{'sent_to'});

    # add to msg object new attachments from CGI POST data that browser sent
    $compose->read_attachments_from_cgi;

    # tell message object to store itself
    if ($compose->store) {
	$self->{controller}->infomsg(!$is_memo ? "Your message has been sent." : "Your memo has been committed.");
	delete $self->{compose_msg};
    } else {
	$self->{controller}->infomsg("There was an error ".(!$is_memo ? "sending your message" : "committing your memo").".  Please contact technical support.");
    }
}

sub verify_new_mailbox {
    my ($self, $new_box) = @_;
    my $controller = $self->{controller};

    # make sure there is a new_box
    if (!$new_box) {
	$controller->infomsg("You did not enter a name for your new mailbox!");
	return 0;
    }
    # make sure there are no commas
    if (($new_box) =~ (m/,/)) {
	$controller->infomsg("Sorry, your mailbox names cannot contain commas (,).  Please try again.");
	return 0;
    }
    # make sure this mailbox name doesn't already exist
    foreach (@{$self->{'mailboxes'}}) {
	if (ucfirst($_) eq ucfirst($new_box)) {
	    $controller->infomsg("You already have a mailbox with the name ".ucfirst($new_box).".  Please pick a different name.");
	    return 0;
	}
    }
    return 1;
}

sub add_new_mailbox {
    my ($self, $new_box) = @_;
    my $controller = $self->{controller};
    my $user = $self->{user_manager}->userprofile('user');

    my @old_boxes = $self->{user_manager}->mailboxes;

    if ($#old_boxes == 14) {
	$controller->infomsg("You already have 15 custom mailboxes, which is the maximum currently allowed.");
	return;
    }

    push(@old_boxes, $new_box);

    if ($self->{user_manager}->mailboxes($user, @old_boxes)) {
	$controller->infomsg("Mailbox ".ucfirst($new_box)." has been created.");
    }
}

sub delete_mailbox {
    my ($self, $old_box, $delete_mail_in_box) = @_;
    my $controller = $self->{controller};
    my $user = $self->{user_manager}->userprofile('user');

    my $num_displaced = $#{$self->{$old_box}->{'index'}} + 1;

Mercury.pm  view on Meta::CPAN

=back

Aside from the names and functions of the above five accessors and two
instance variables, the controller class has no other restraints.
You will likely want to simply add these accessors and variables to an
existing class in your application.

Provided in this distribution is the Apache::App::Mercury::Controller
class, which is an example (almost usable) Controller class which
illustrates how your Controller should interact with Apache::App::Mercury.

=head2 Display class

Provided with this distribution is the Apache::App::Mercury::Display class,
which implements all view-specific methods for the Apache::App::Mercury
application.  If you want to change or extend the look, then you can subclass
Apache::App::Mercury::Display and add or override its methods.

=head2 UserManager class

Apache::App::Mercury needs some way to get information about the user
accounts in your application.  It does this through a user manager
class (which would be part of the data model in an MVC design).
Your user manager class should implement the following methods:

=over 4

=item * userprofile()

=item * get_userinfo()

=item * mailboxes()

=item * mail_trans_filter()

=item * auto_forward()

=back

For explanations of what these methods should do, see the
Apache::App::Mercury::UserManager manpage.

=head1 DATABASE SETUP

Currently, Apache::App::Mercury only supports MySQL for its message backing
store.  Adding support for other databases should be fairly straightforward -
I invite anyone to take the initiative of doing it.

You need to create a MySQL database, set the variable
Apache::App::Mercury::Config::DBI_CONNECT_STR, and create the following two
tables in the database you just created:

 CREATE TABLE messages (
  id          int(10) unsigned DEFAULT '0' NOT NULL auto_increment,
  recipient   varchar(16) DEFAULT '' NOT NULL,
  sent_to     varchar(255) DEFAULT '' NOT NULL,
  sender      varchar(16) DEFAULT '' NOT NULL,
  timestamp   timestamp(14),
  subject     varchar(100),
  body        text,
  attachments text NOT NULL,
  status      enum('unread','read','replied','forwarded','deleted') DEFAULT 'unread',
  status_sender enum('unread','read','replied','forwarded','deleted') DEFAULT 'unread',
  status_smtp enum('unsent','sent','checked') DEFAULT 'unsent' NOT NULL,
  code        varchar(15) DEFAULT '' NOT NULL,
  box         varchar(16) DEFAULT '' NOT NULL,
  trans       enum('hide','show') DEFAULT 'hide' NOT NULL,
  security    enum('low','medium','high') DEFAULT 'medium',
  PRIMARY KEY (id),
  KEY         recipient (recipient),
  KEY         timestamp (timestamp),
  KEY         sender (sender),
  KEY         code (code),
  KEY         box (box),
  KEY         sent_to (sent_to(34)),
  KEY         trans (trans),
  KEY         status_smtp (status_smtp)
 );

 CREATE TABLE message_attachments (
  aid         int(10) unsigned DEFAULT '0' NOT NULL auto_increment,
  filesys     char(255) DEFAULT '' NOT NULL,
  attachment  char(255) DEFAULT '' NOT NULL,
  msg_ids     char(255) DEFAULT '' NOT NULL,
  PRIMARY KEY (aid),
  UNIQUE      filesys (filesys)
 );

=head1 ACCESSORS

=over 4

=item controller()

Returns the Controller object which was originally set by the
initialize($ctrlr_obj) method.

=item user_manager()

Returns the UserManager object which was instantiated in the
initialize() method using Apache::App::Mercury::Config::USER_MANAGER_CLASS.

=back

=head1 METHODS

Not yet documented.

=head1 BUGS

Maybe a few mosquitos, some spiders, a sweat fly, and an ant colony.
In other words, probably many.  In particular, the installation procedure
might need some work.  Feel free to e-mail any problems you
encounter while trying to install/configure for your site.

=head1 AUTHORS

Adi Fairbank <adi@adiraj.org>

Thanks to Tyler Kendall <tyler@pidgeonenglish.com> for help with
implementation of the ancestor version of this software (the concept
on which this software is based).

=head1 COPYRIGHT

Copyright (c) 2003 - Adi Fairbank

This software (Apache::App::Mercury and all related Perl modules under
the Apache::App::Mercury namespace) is copyright Adi Fairbank.

=head1 COPYLEFT (LICENSE)

This module is free software; you can redistribute it and/or modify it
under the terms of either:

  a) the GNU General Public License as published by the Free Software
     Foundation; either version 1, or (at your option) any later version,

  or

  b) the "Artistic License" which comes with this module.

This program is distributed in the hope that it will be useful, but WITHOUT



( run in 0.401 second using v1.01-cache-2.11-cpan-e1769b4cff6 )