/[notice-sender]/trunk/Nos.pm
This is repository of my old source code which isn't updated any more. Go to git.rot13.org for current projects!
ViewVC logotype

Diff of /trunk/Nos.pm

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 47 by dpavlin, Tue May 24 14:02:05 2005 UTC revision 63 by dpavlin, Wed Jun 22 16:42:06 2005 UTC
# Line 16  our @EXPORT_OK = ( @{ $EXPORT_TAGS{'all' Line 16  our @EXPORT_OK = ( @{ $EXPORT_TAGS{'all'
16  our @EXPORT = qw(  our @EXPORT = qw(
17  );  );
18    
19  our $VERSION = '0.4';  our $VERSION = '0.5';
20    
21  use Class::DBI::Loader;  use Class::DBI::Loader;
22  use Email::Valid;  use Email::Valid;
# Line 26  use Email::Auth::AddressHash; Line 26  use Email::Auth::AddressHash;
26  use Email::Simple;  use Email::Simple;
27  use Email::Address;  use Email::Address;
28  use Mail::DeliveryStatus::BounceParser;  use Mail::DeliveryStatus::BounceParser;
29  use Data::Dumper;  use Class::DBI::AbstractSearch;
   
 my $email_send_driver = 'Email::Send::IO';  
 my @email_send_options;  
   
 #$email_send_driver = 'Sendmail';  
30    
31    
32  =head1 NAME  =head1 NAME
# Line 45  Nos - Notice Sender core module Line 40  Nos - Notice Sender core module
40    
41  =head1 DESCRIPTION  =head1 DESCRIPTION
42    
43  Core module for notice sender's functionality.  Notice sender is mail handler. It is not MTA, since it doesn't know how to
44    receive e-mails or send them directly to other hosts. It is not mail list
45    manager because it requires programming to add list members and send
46    messages. You can think of it as mechanisam for off-loading your e-mail
47    sending to remote server using SOAP service.
48    
49    It's concept is based around B<lists>. Each list can have zero or more
50    B<members>. Each list can have zero or more B<messages>.
51    
52    Here comes a twist: each outgoing message will have unique e-mail generated,
53    so Notice Sender will be able to link received replies (or bounces) with
54    outgoing messages.
55    
56    It doesn't do much more than that. It B<can't> create MIME encoded e-mail,
57    send attachments, handle 8-bit characters in headers (which have to be
58    encoded) or anything else.
59    
60    It will just queue your e-mail message to particular list (sending it to
61    possibly remote Notice Sender SOAP server just once), send it out at
62    reasonable rate (so that it doesn't flood your e-mail infrastructure) and
63    track replies.
64    
65    It is best used to send smaller number of messages to more-or-less fixed
66    list of recipients while allowing individual responses to be examined.
67    Tipical use include replacing php e-mail sending code with SOAP call to
68    Notice Sender. It does support additional C<ext_id> field for each member
69    which can be used to track some unique identifier from remote system for
70    particular user.
71    
72    It comes with command-line utility C<sender.pl> which can be used to perform
73    all available operation from scripts (see C<perldoc sender.pl>).
74    This command is also useful for debugging while writing client SOAP
75    application.
76    
77  =head1 METHODS  =head1 METHODS
78    
# Line 80  sub new { Line 107  sub new {
107                  user            => $self->{'user'},                  user            => $self->{'user'},
108                  password        => $self->{'passwd'},                  password        => $self->{'passwd'},
109                  namespace       => "Nos",                  namespace       => "Nos",
110  #               additional_classes      => qw/Class::DBI::AbstractSearch/,                  additional_classes      => qw/Class::DBI::AbstractSearch/,
111  #               additional_base_classes => qw/My::Stuff/,  #               additional_base_classes => qw/My::Stuff/,
112                  relationships   => 1,                  relationships   => 1,
113          ) || croak "can't init Class::DBI::Loader";          ) || croak "can't init Class::DBI::Loader";
# Line 104  C<email> address. Line 131  C<email> address.
131    
132  Returns ID of newly created list.  Returns ID of newly created list.
133    
134  Calls internally L<_add_list>, see details there.  Calls internally C<_add_list>, see details there.
135    
136  =cut  =cut
137    
# Line 114  sub new_list { Line 141  sub new_list {
141          my $arg = {@_};          my $arg = {@_};
142    
143          confess "need list name" unless ($arg->{'list'});          confess "need list name" unless ($arg->{'list'});
144          confess "need list email" unless ($arg->{'list'});          confess "need list email" unless ($arg->{'email'});
145    
146            $arg->{'list'} = lc($arg->{'list'});
147            $arg->{'email'} = lc($arg->{'email'});
148    
149          my $l = $self->_get_list($arg->{'list'}) ||          my $l = $self->_get_list($arg->{'list'}) ||
150                  $self->_add_list( @_ ) ||                  $self->_add_list( @_ ) ||
# Line 124  sub new_list { Line 154  sub new_list {
154  }  }
155    
156    
157    =head2 delete_list
158    
159    Delete list from database.
160    
161     my $ok = delete_list(
162            list => 'My list'
163     );
164    
165    Returns false if list doesn't exist.
166    
167    =cut
168    
169    sub delete_list {
170            my $self = shift;
171    
172            my $args = {@_};
173    
174            croak "need list to delete" unless ($args->{'list'});
175    
176            $args->{'list'} = lc($args->{'list'});
177    
178            my $lists = $self->{'loader'}->find_class('lists');
179    
180            my $this_list = $lists->search( name => $args->{'list'} )->first || return;
181    
182            $this_list->delete || croak "can't delete list\n";
183    
184            return $lists->dbi_commit || croak "can't commit";
185    }
186    
187    
188  =head2 add_member_to_list  =head2 add_member_to_list
189    
190  Add new member to list  Add new member to list
# Line 132  Add new member to list Line 193  Add new member to list
193          list => "My list",          list => "My list",
194          email => "john.doe@example.com",          email => "john.doe@example.com",
195          name => "John A. Doe",          name => "John A. Doe",
196            ext_id => 42,
197   );   );
198    
199  C<name> parametar is optional.  C<name> and C<ext_id> parametars are optional.
200    
201  Return member ID if user is added.  Return member ID if user is added.
202    
# Line 145  sub add_member_to_list { Line 207  sub add_member_to_list {
207    
208          my $arg = {@_};          my $arg = {@_};
209    
210          my $email = $arg->{'email'} || croak "can't add user without e-mail";          my $email = lc($arg->{'email'}) || croak "can't add user without e-mail";
211          my $name = $arg->{'name'} || '';          my $name = $arg->{'name'} || '';
212          my $list_name = $arg->{'list'} || croak "need list name";          my $list_name = lc($arg->{'list'}) || croak "need list name";
213            my $ext_id = $arg->{'ext_id'};
214    
215          my $list = $self->_get_list($list_name) || croak "list $list_name doesn't exist";          my $list = $self->_get_list($list_name) || croak "list $list_name doesn't exist";
216    
# Line 170  sub add_member_to_list { Line 233  sub add_member_to_list {
233                  $this_user->update;                  $this_user->update;
234          }          }
235    
236            if (defined($ext_id) && ($this_user->ext_id || '') ne $ext_id) {
237                    $this_user->ext_id($ext_id);
238                    $this_user->update;
239            }
240    
241          my $user_on_list = $user_list->find_or_create({          my $user_on_list = $user_list->find_or_create({
242                  user_id => $this_user->id,                  user_id => $this_user->id,
243                  list_id => $list->id,                  list_id => $list->id,
# Line 197  Returns array of hashes with user inform Line 265  Returns array of hashes with user inform
265          email => 'dpavlin@rot13.org          email => 'dpavlin@rot13.org
266   }   }
267    
268  If list is not found, returns false.  If list is not found, returns false. If there is C<ext_id> in user data,
269    it will also be returned.
270    
271  =cut  =cut
272    
# Line 206  sub list_members { Line 275  sub list_members {
275    
276          my $args = {@_};          my $args = {@_};
277    
278          my $list_name = $args->{'list'} || confess "need list name";          my $list_name = lc($args->{'list'}) || confess "need list name";
279    
280          my $lists = $self->{'loader'}->find_class('lists');          my $lists = $self->{'loader'}->find_class('lists');
281          my $user_list = $self->{'loader'}->find_class('user_list');          my $user_list = $self->{'loader'}->find_class('user_list');
# Line 221  sub list_members { Line 290  sub list_members {
290                          email => $user_on_list->user_id->email,                          email => $user_on_list->user_id->email,
291                  };                  };
292    
293                    my $ext_id = $user_on_list->user_id->ext_id;
294                    $row->{'ext_id'} = $ext_id if (defined($ext_id));
295    
296                  push @results, $row;                  push @results, $row;
297          }          }
298    
# Line 243  Delete member from database. Line 315  Delete member from database.
315    
316  Returns false if user doesn't exist.  Returns false if user doesn't exist.
317    
318    This function will delete member from all lists (by cascading delete), so it
319    shouldn't be used lightly.
320    
321  =cut  =cut
322    
323  sub delete_member {  sub delete_member {
# Line 252  sub delete_member { Line 327  sub delete_member {
327    
328          croak "need name or email of user to delete" unless ($args->{'name'} || $args->{'email'});          croak "need name or email of user to delete" unless ($args->{'name'} || $args->{'email'});
329    
330            $args->{'email'} = lc($args->{'email'}) if ($args->{'email'});
331    
332          my $key = 'name';          my $key = 'name';
333          $key = 'email' if ($args->{'email'});          $key = 'email' if ($args->{'email'});
334    
# Line 259  sub delete_member { Line 336  sub delete_member {
336    
337          my $this_user = $users->search( $key => $args->{$key} )->first || return;          my $this_user = $users->search( $key => $args->{$key} )->first || return;
338    
 print Dumper($this_user);  
   
339          $this_user->delete || croak "can't delete user\n";          $this_user->delete || croak "can't delete user\n";
340    
341          return $users->dbi_commit || croak "can't commit";          return $users->dbi_commit || croak "can't commit";
342  }  }
343    
344    =head2 delete_member_from_list
345    
346    Delete member from particular list.
347    
348     my $ok = delete_member_from_list(
349            list => 'My list',
350            email => 'dpavlin@rot13.org',
351     );
352    
353    Returns false if user doesn't exist on that particular list.
354    
355    It will die if list or user doesn't exist. You have been warned (you might
356    want to eval this functon to prevent it from croaking).
357    
358    =cut
359    
360    sub delete_member_from_list {
361            my $self = shift;
362    
363            my $args = {@_};
364    
365            croak "need list name and email of user to delete" unless ($args->{'list'} && $args->{'email'});
366    
367            $args->{'list'} = lc($args->{'list'});
368            $args->{'email'} = lc($args->{'email'});
369    
370            my $user = $self->{'loader'}->find_class('users');
371            my $list = $self->{'loader'}->find_class('lists');
372            my $user_list = $self->{'loader'}->find_class('user_list');
373    
374            my $this_user = $user->search( email => $args->{'email'} )->first || croak "can't find user: ".$args->{'email'};
375            my $this_list = $list->search( name => $args->{'list'} )->first || croak "can't find list: ".$args->{'list'};
376    
377            my $this_user_list = $user_list->search_where( list_id => $this_list->id, user_id => $this_user->id )->first || return;
378    
379            $this_user_list->delete || croak "can't delete user from list\n";
380    
381            return $user_list->dbi_commit || croak "can't commit";
382    }
383    
384  =head2 add_message_to_list  =head2 add_message_to_list
385    
386  Adds message to one list's queue for later sending.  Adds message to one list's queue for later sending.
# Line 291  sub add_message_to_list { Line 406  sub add_message_to_list {
406    
407          my $args = {@_};          my $args = {@_};
408    
409          my $list_name = $args->{'list'} || confess "need list name";          my $list_name = lc($args->{'list'}) || confess "need list name";
410          my $message_text = $args->{'message'} || croak "need message";          my $message_text = $args->{'message'} || croak "need message";
411    
412          my $m = Email::Simple->new($message_text) || croak "can't parse message";          my $m = Email::Simple->new($message_text) || croak "can't parse message";
# Line 332  sub add_message_to_list { Line 447  sub add_message_to_list {
447    
448  Send queued messages or just ones for selected list  Send queued messages or just ones for selected list
449    
450   $nos->send_queued_messages("My list",'smtp');   $nos->send_queued_messages(
451            list => 'My list',
452            driver => 'smtp',
453            sleep => 3,
454     );
455    
456  Second option is driver which will be used for e-mail delivery. If not  Second option is driver which will be used for e-mail delivery. If not
457  specified, C<IO> driver will be used which will dump e-mail to C<STDERR>.  specified, C<IO> driver will be used which will dump e-mail to C<STDERR>.
# Line 347  Send e-mail using SMTP server at 127.0.0 Line 466  Send e-mail using SMTP server at 127.0.0
466    
467  =back  =back
468    
469    Default sleep wait between two messages is 3 seconds.
470    
471  =cut  =cut
472    
473  sub send_queued_messages {  sub send_queued_messages {
474          my $self = shift;          my $self = shift;
475    
476          my $list_name = shift;          my $arg = {@_};
477    
478            my $list_name = lc($arg->{'list'}) || '';
479            my $driver = $arg->{'driver'} || '';
480            my $sleep = $arg->{'sleep'};
481            $sleep ||= 3 unless defined($sleep);
482    
483          my $driver = shift || '';          my $email_send_driver = 'Email::Send::IO';
484            my @email_send_options;
485    
486          if (lc($driver) eq 'smtp') {          if (lc($driver) eq 'smtp') {
487                  $email_send_driver = 'Email::Send::SMTP';                  $email_send_driver = 'Email::Send::SMTP';
488                  @email_send_options = ['127.0.0.1'];                  @email_send_options = ['127.0.0.1'];
489            } else {
490                    warn "dumping all messages to STDERR\n";
491          }          }
         warn "using $driver [$email_send_driver]\n";  
492    
493          my $lists = $self->{'loader'}->find_class('lists');          my $lists = $self->{'loader'}->find_class('lists');
494          my $queue = $self->{'loader'}->find_class('queue');          my $queue = $self->{'loader'}->find_class('queue');
# Line 401  sub send_queued_messages { Line 529  sub send_queued_messages {
529    
530                                  my $from_addr;                                  my $from_addr;
531                                  my $from_email_only = $from . "+" . $hash . ( $domain ? '@' . $domain : '');                                  my $from_email_only = $from . "+" . $hash . ( $domain ? '@' . $domain : '');
532    
533                                  $from_addr .= '"' . $u->list_id->from_addr . '" ' if ($u->list_id->from_addr);                                  $from_addr .= '"' . $u->list_id->from_addr . '" ' if ($u->list_id->from_addr);
534                                  $from_addr .= '<' . $from_email_only . '>';                                  $from_addr .= '<' . $from_email_only . '>';
535                                  my $to = '"' . $u->user_id->name . '" <' . $to_email . '>';                                  my $to = '"' . $u->user_id->name . '" <' . $to_email . '>';
# Line 408  sub send_queued_messages { Line 537  sub send_queued_messages {
537                                  my $m_obj = Email::Simple->new($msg) || croak "can't parse message";                                  my $m_obj = Email::Simple->new($msg) || croak "can't parse message";
538    
539                                  $m_obj->header_set('Return-Path', $from_email_only) || croak "can't set Return-Path: header";                                  $m_obj->header_set('Return-Path', $from_email_only) || croak "can't set Return-Path: header";
540                                  $m_obj->header_set('Sender', $from_email_only) || croak "can't set Return-Path: header";                                  $m_obj->header_set('Sender', $from_email_only) || croak "can't set Sender: header";
541                                  $m_obj->header_set('Errors-To', $from_email_only) || croak "can't set Return-Path: header";                                  $m_obj->header_set('Errors-To', $from_email_only) || croak "can't set Errors-To: header";
542                                  $m_obj->header_set('From', $from_addr) || croak "can't set From: header";                                  $m_obj->header_set('From', $from_addr) || croak "can't set From: header";
543                                  $m_obj->header_set('To', $to) || croak "can't set To: header";                                  $m_obj->header_set('To', $to) || croak "can't set To: header";
544    
# Line 429  sub send_queued_messages { Line 558  sub send_queued_messages {
558                                          hash => $hash,                                          hash => $hash,
559                                  });                                  });
560                                  $sent->dbi_commit;                                  $sent->dbi_commit;
561    
562                                    if ($sleep) {
563                                            warn "sleeping $sleep seconds\n";
564                                            sleep($sleep);
565                                    }
566                          }                          }
567                  }                  }
568                  $m->all_sent(1);                  $m->all_sent(1);
# Line 447  Receive single message for list's inbox. Line 581  Receive single message for list's inbox.
581          message => $message,          message => $message,
582   );   );
583    
584    This method is used by C<sender.pl> when receiving e-mail messages.
585    
586  =cut  =cut
587    
588  sub inbox_message {  sub inbox_message {
# Line 457  sub inbox_message { Line 593  sub inbox_message {
593          return unless ($arg->{'message'});          return unless ($arg->{'message'});
594          croak "need list name" unless ($arg->{'list'});          croak "need list name" unless ($arg->{'list'});
595    
596            $arg->{'list'} = lc($arg->{'list'});
597    
598          my $this_list = $self->_get_list($arg->{'list'}) || croak "can't find list ".$arg->{'list'}."\n";          my $this_list = $self->_get_list($arg->{'list'}) || croak "can't find list ".$arg->{'list'}."\n";
599    
600          my $m = Email::Simple->new($arg->{'message'}) || croak "can't parse message";          my $m = Email::Simple->new($arg->{'message'}) || croak "can't parse message";
601    
602          my $to = $m->header('To') || die "can't find To: address in incomming message\n";          my $to = $m->header('To') || die "can't find To: address in incomming message\n";
603    
604            my $return_path = $m->header('Return-Path') || '';
605    
606          my @addrs = Email::Address->parse( $to );          my @addrs = Email::Address->parse( $to );
607    
608          die "can't parse To: $to address\n" unless (@addrs);          die "can't parse To: $to address\n" unless (@addrs);
# Line 472  sub inbox_message { Line 612  sub inbox_message {
612          my $hash;          my $hash;
613    
614          foreach my $a (@addrs) {          foreach my $a (@addrs) {
615                  if ($a->address =~ m/\+([a-f0-9]{$hl})@/) {                  if ($a->address =~ m/\+([a-f0-9]{$hl})@/i) {
616                          $hash = $1;                          $hash = $1;
617                          last;                          last;
618                  }                  }
619          }          }
620    
621          croak "can't find hash in e-mail $to\n" unless ($hash);          #warn "can't find hash in e-mail $to\n" unless ($hash);
622    
623          my $sent = $self->{'loader'}->find_class('sent');          my $sent = $self->{'loader'}->find_class('sent');
624    
625          # will use null if no matching message_id is found          # will use null if no matching message_id is found
626          my $sent_msg = $sent->search( hash => $hash )->first;          my $sent_msg;
627            $sent_msg = $sent->search( hash => $hash )->first if ($hash);
628    
629          my ($message_id, $user_id) = (undef, undef);    # init with NULL          my ($message_id, $user_id) = (undef, undef);    # init with NULL
630    
# Line 491  sub inbox_message { Line 632  sub inbox_message {
632                  $message_id = $sent_msg->message_id || carp "no message_id";                  $message_id = $sent_msg->message_id || carp "no message_id";
633                  $user_id = $sent_msg->user_id || carp "no user_id";                  $user_id = $sent_msg->user_id || carp "no user_id";
634          } else {          } else {
635                  warn "can't find sender with hash $hash\n";                  #warn "can't find sender with hash $hash\n";
636                    my $users = $self->{'loader'}->find_class('users');
637                    my $from = $m->header('From');
638                    $from = $1 if ($from =~ m/<(.*)>/);
639                    my $this_user = $users->search( email => lc($from) )->first;
640                    $user_id = $this_user->id if ($this_user);
641          }          }
642    
643    
644          my $is_bounce = 0;          my $is_bounce = 0;
645    
646          {          if ($return_path eq '<>' || $return_path eq '') {
647                  no warnings;                  no warnings;
648                  my $bounce = eval { Mail::DeliveryStatus::BounceParser->new(                  my $bounce = eval { Mail::DeliveryStatus::BounceParser->new(
649                          $arg->{'message'}, { report_non_bounces=>1 },                          $arg->{'message'}, { report_non_bounces=>1 },
650                  ) };                  ) };
651                  carp "can't check if this message is bounce!" if ($@);                  #warn "can't check if this message is bounce!" if ($@);
652                    
653                  $is_bounce++ if ($bounce && $bounce->is_bounce);                  $is_bounce++ if ($bounce && $bounce->is_bounce);
654          }          }
# Line 519  sub inbox_message { Line 665  sub inbox_message {
665    
666          $this_received->dbi_commit;          $this_received->dbi_commit;
667    
668          print "message_id: ",($message_id || "not found")," -- $is_bounce\n";  #       print "message_id: ",($message_id || "not found")," -- $is_bounce\n";
   
   
         warn "inbox is not yet implemented";  
669  }  }
670    
671    
# Line 554  sub _add_list { Line 697  sub _add_list {
697    
698          my $arg = {@_};          my $arg = {@_};
699    
700          my $name = $arg->{'list'} || confess "can't add list without name";          my $name = lc($arg->{'list'}) || confess "can't add list without name";
701          my $email = $arg->{'email'} || confess "can't add list without e-mail";          my $email = lc($arg->{'email'}) || confess "can't add list without e-mail";
702          my $from_addr = $arg->{'from'};          my $from_addr = $arg->{'from'};
703    
704          my $lists = $self->{'loader'}->find_class('lists');          my $lists = $self->{'loader'}->find_class('lists');
# Line 596  sub _get_list { Line 739  sub _get_list {
739    
740          my $lists = $self->{'loader'}->find_class('lists') || confess "can't find lists class";          my $lists = $self->{'loader'}->find_class('lists') || confess "can't find lists class";
741    
742          return $lists->search({ name => $name })->first;          return $lists->search({ name => lc($name) })->first;
743  }  }
744    
745  ###  ###
# Line 638  sub new { Line 781  sub new {
781    
782   $message_id = NewList(   $message_id = NewList(
783          list => 'My list',          list => 'My list',
784            from => 'Name of my list',
785          email => 'my-list@example.com'          email => 'my-list@example.com'
786   );   );
787    
# Line 648  sub NewList { Line 792  sub NewList {
792    
793          if ($_[0] !~ m/^HASH/) {          if ($_[0] !~ m/^HASH/) {
794                  return $nos->new_list(                  return $nos->new_list(
795                          list => $_[0], email => $_[1],                          list => $_[0], from => $_[1], email => $_[2],
796                  );                  );
797          } else {          } else {
798                  return $nos->new_list( %{ shift @_ } );                  return $nos->new_list( %{ shift @_ } );
# Line 656  sub NewList { Line 800  sub NewList {
800  }  }
801    
802    
803    =head2 DeleteList
804    
805     $ok = DeleteList(
806            list => 'My list',
807     );
808    
809    =cut
810    
811    sub DeleteList {
812            my $self = shift;
813    
814            if ($_[0] !~ m/^HASH/) {
815                    return $nos->delete_list(
816                            list => $_[0],
817                    );
818            } else {
819                    return $nos->delete_list( %{ shift @_ } );
820            }
821    }
822    
823  =head2 AddMemberToList  =head2 AddMemberToList
824    
825   $member_id = AddMemberToList(   $member_id = AddMemberToList(
826          list => 'My list',          list => 'My list',
827          email => 'e-mail@example.com',          email => 'e-mail@example.com',
828          name => 'Full Name'          name => 'Full Name',
829            ext_id => 42,
830   );   );
831    
832  =cut  =cut
# Line 671  sub AddMemberToList { Line 836  sub AddMemberToList {
836    
837          if ($_[0] !~ m/^HASH/) {          if ($_[0] !~ m/^HASH/) {
838                  return $nos->add_member_to_list(                  return $nos->add_member_to_list(
839                          list => $_[0], email => $_[1], name => $_[2],                          list => $_[0], email => $_[1], name => $_[2], ext_id => $_[4],
840                  );                  );
841          } else {          } else {
842                  return $nos->add_member_to_list( %{ shift @_ } );                  return $nos->add_member_to_list( %{ shift @_ } );
# Line 687  sub AddMemberToList { Line 852  sub AddMemberToList {
852    
853  Returns array of hashes with user informations, see C<list_members>.  Returns array of hashes with user informations, see C<list_members>.
854    
855    Returning arrays from SOAP calls is somewhat fuzzy (at least to me). It
856    seems that SOAP::Lite client thinks that it has array with one element which
857    is array of hashes with data.
858    
859  =cut  =cut
860    
861  sub ListMembers {  sub ListMembers {
# Line 700  sub ListMembers { Line 869  sub ListMembers {
869                  $list_name = $_[0]->{'list'};                  $list_name = $_[0]->{'list'};
870          }          }
871    
872          return $nos->list_members( list => $list_name );          return [ $nos->list_members( list => $list_name ) ];
873  }  }
874    
875    
876    =head2 DeleteMemberFromList
877    
878     $member_id = DeleteMemberFromList(
879            list => 'My list',
880            email => 'e-mail@example.com',
881     );
882    
883    =cut
884    
885    sub DeleteMemberFromList {
886            my $self = shift;
887    
888            if ($_[0] !~ m/^HASH/) {
889                    return $nos->delete_member_from_list(
890                            list => $_[0], email => $_[1],
891                    );
892            } else {
893                    return $nos->delete_member_from_list( %{ shift @_ } );
894            }
895    }
896    
897    
898  =head2 AddMessageToList  =head2 AddMessageToList
899    
900   $message_id = AddMessageToList(   $message_id = AddMessageToList(

Legend:
Removed from v.47  
changed lines
  Added in v.63

  ViewVC Help
Powered by ViewVC 1.1.26