Projekt

Allgemein

Profil

« Zurück | Weiter » 

Revision 8f3ecba9

Von Moritz Bunkus vor mehr als 16 Jahren hinzugefügt

  • ID 8f3ecba98c0f85f2b48735c1ac110c3c9d957100
  • Vorgänger 01bdb4dc
  • Nachfolger 16d8d326

Beim Verschicken von Emails müssen die Absender- und Empfängeradressen MIME-Encodiert werden.

Unterschiede anzeigen:

SL/Mailer.pm
30 30

  
31 31
package Mailer;
32 32

  
33
use Email::Address;
34

  
33 35
use SL::Common;
34 36
use SL::Template;
35 37

  
......
97 99
  local (*IN, *OUT);
98 100

  
99 101
  $num_sent++;
100
  my $boundary = time() . "-$$-${num_sent}";
101
  $boundary    =  "LxOffice-$self->{version}-$boundary";
102
  my $domain   =  $self->{from};
103
  $domain      =~ s/(.*?\@|>)//g;
104
  my $msgid    =  "$boundary\@$domain";
105

  
106
  my $form     =  $main::form;
107
  my $myconfig =  \%main::myconfig;
108

  
109
  my $email    =  $myconfig->{email};
110
  $email       =~ s/[^\w\.\-\+=@]//ig;
102
  my $boundary    = time() . "-$$-${num_sent}";
103
  $boundary       =  "LxOffice-$self->{version}-$boundary";
104
  my $domain      =  $self->{from};
105
  $domain         =~ s/(.*?\@|>)//g;
106
  my $msgid       =  "$boundary\@$domain";
111 107

  
112
  $form->{myconfig_email} = $email;
108
  my $form        =  $main::form;
109
  my $myconfig    =  \%main::myconfig;
113 110

  
114
  my $template =  PlainTextTemplate->new(undef, $form, $myconfig);
115
  my $sendmail =  $template->parse_block($main::sendmail);
111
  my $email       =  $myconfig->{email};
112
  $email          =~ s/[^\w\.\-\+=@]//ig;
116 113

  
117
  $self->{charset} = Common::DEFAULT_CHARSET unless $self->{charset};
114
  my %temp_form   = ( %{ $form }, 'myconfig_email' => $email );
115
  my $template    = PlainTextTemplate->new(undef, \%temp_form, $myconfig);
116
  my $sendmail    = $template->parse_block($main::sendmail);
118 117

  
119 118
  if (!open(OUT, $sendmail)) {
120 119
    $main::lxdebug->leave_sub();
121 120
    return "$sendmail : $!";
122 121
  }
123 122

  
124
  $self->{contenttype} = "text/plain" unless $self->{contenttype};
125

  
126
  my ($cc, $bcc);
127
  $cc  = "Cc: $self->{cc}\n"   if $self->{cc};
128
  $bcc = "Bcc: $self->{bcc}\n" if $self->{bcc};
123
  $self->{charset}     ||= Common::DEFAULT_CHARSET;
124
  $self->{contenttype} ||= "text/plain";
129 125

  
130 126
  foreach my $item (qw(to cc bcc)) {
127
    next unless ($self->{$item});
131 128
    $self->{$item} =~ s/\&lt;/</g;
132 129
    $self->{$item} =~ s/\$<\$/</g;
133 130
    $self->{$item} =~ s/\&gt;/>/g;
134 131
    $self->{$item} =~ s/\$>\$/>/g;
135 132
  }
136 133

  
137
  my $subject = $self->mime_quote_text($self->{subject}, 60);
134
  my $headers = '';
135
  foreach my $item (qw(from to cc)) {
136
    next unless ($self->{$item});
137
    my (@addr_objects) = Email::Address->parse($self->{$item});
138
    next unless (scalar @addr_objects);
139

  
140
    foreach my $addr_obj (@addr_objects) {
141
      $addr_obj->phrase($self->mime_quote_text($addr_obj->phrase(), 60))   if ($addr_obj->phrase());
142
      $addr_obj->comment($self->mime_quote_text($addr_obj->comment(), 60)) if ($addr_obj->comment());
143

  
144
      $headers .= sprintf("%s: %s\n", ucfirst($item), $addr_obj->format());
145
    }
146
  }
147

  
148
  $headers .= sprintf("Subject: %s\n", $self->mime_quote_text($self->{subject}, 60));
138 149

  
139
  print OUT qq|From: $self->{from}
140
To: $self->{to}
141
${cc}${bcc}Subject: $subject
142
Message-ID: <$msgid>
150
  print OUT qq|${headers}Message-ID: <$msgid>
143 151
X-Mailer: Lx-Office $self->{version}
144 152
MIME-Version: 1.0
145 153
|;
doc/modules/LICENSE.Email-Address
1
Copyright (c) 2004 Casey West.  All rights reserved.
2

  
3
This module is free software; you can redistribute it and/or modify it
4
under the same terms as Perl itself.
5

  
6
Perl is distributed under your choice of the GNU General Public License or
7
the Artistic License.
8

  
9
The complete text of the GNU General Public License can be found in
10
/usr/share/common-licenses/GPL and the Artistic Licence can be found
11
in /usr/share/common-licenses/Artistic.
modules/fallback/Email/Address.pm
1
package Email::Address;
2
use strict;
3
## no critic RequireUseWarnings
4
# support pre-5.6
5

  
6
use vars qw[$VERSION $COMMENT_NEST_LEVEL $STRINGIFY
7
            $COLLAPSE_SPACES
8
            %PARSE_CACHE %FORMAT_CACHE %NAME_CACHE
9
            $addr_spec $angle_addr $name_addr $mailbox];
10

  
11
my $NOCACHE;
12

  
13
$VERSION              = '1.888';
14
$COMMENT_NEST_LEVEL ||= 2;
15
$STRINGIFY          ||= 'format';
16
$COLLAPSE_SPACES      = 1 unless defined $COLLAPSE_SPACES; # who wants //=? me!
17

  
18
=head1 NAME
19

  
20
Email::Address - RFC 2822 Address Parsing and Creation
21

  
22
=head1 SYNOPSIS
23

  
24
  use Email::Address;
25

  
26
  my @addresses = Email::Address->parse($line);
27
  my $address   = Email::Address->new(Casey => 'casey@localhost');
28

  
29
  print $address->format;
30

  
31
=head1 VERSION
32

  
33
version 1.886
34

  
35
 $Id: /my/pep/Email-Address/trunk/lib/Email/Address.pm 31900 2007-06-23T01:25:34.344997Z rjbs  $
36

  
37
=head1 DESCRIPTION
38

  
39
This class implements a regex-based RFC 2822 parser that locates email
40
addresses in strings and returns a list of C<Email::Address> objects found.
41
Alternatley you may construct objects manually. The goal of this software is to
42
be correct, and very very fast.
43

  
44
=cut
45

  
46
my $CTL            = q{\x00-\x1F\x7F};
47
my $special        = q{()<>\\[\\]:;@\\\\,."};
48

  
49
my $text           = qr/[^\x0A\x0D]/;
50

  
51
my $quoted_pair    = qr/\\$text/;
52

  
53
my $ctext          = qr/(?>[^()\\]+)/;
54
my ($ccontent, $comment) = (q{})x2;
55
for (1 .. $COMMENT_NEST_LEVEL) {
56
  $ccontent = qr/$ctext|$quoted_pair|$comment/;
57
  $comment  = qr/\s*\((?:\s*$ccontent)*\s*\)\s*/;
58
}
59
my $cfws           = qr/$comment|\s+/;
60

  
61
my $atext          = qq/[^$CTL$special\\s]/;
62
my $atom           = qr/$cfws*$atext+$cfws*/;
63
my $dot_atom_text  = qr/$atext+(?:\.$atext+)*/;
64
my $dot_atom       = qr/$cfws*$dot_atom_text$cfws*/;
65

  
66
my $qtext          = qr/[^\\"]/;
67
my $qcontent       = qr/$qtext|$quoted_pair/;
68
my $quoted_string  = qr/$cfws*"$qcontent+"$cfws*/;
69

  
70
my $word           = qr/$atom|$quoted_string/;
71

  
72
# XXX: This ($phrase) used to just be: my $phrase = qr/$word+/; It was changed
73
# to resolve bug 22991, creating a significant slowdown.  Given current speed
74
# problems.  Once 16320 is resolved, this section should be dealt with.
75
# -- rjbs, 2006-11-11
76
#my $obs_phrase     = qr/$word(?:$word|\.|$cfws)*/;
77

  
78
# XXX: ...and the above solution caused endless problems (never returned) when
79
# examining this address, now in a test:
80
#   admin+=E6=96=B0=E5=8A=A0=E5=9D=A1_Weblog-- ATAT --test.socialtext.com
81
# So we disallow the hateful CFWS in this context for now.  Of modern mail
82
# agents, only Apple Web Mail 2.0 is known to produce obs-phrase.
83
# -- rjbs, 2006-11-19
84
my $simple_word    = qr/$atom|\.|\s*"$qcontent+"\s*/;
85
my $obs_phrase     = qr/$simple_word+/;
86

  
87
my $phrase         = qr/$obs_phrase|(?:$word+)/;
88

  
89
my $local_part     = qr/$dot_atom|$quoted_string/;
90
my $dtext          = qr/[^\[\]\\]/;
91
my $dcontent       = qr/$dtext|$quoted_pair/;
92
my $domain_literal = qr/$cfws*\[(?:\s*$dcontent)*\s*\]$cfws*/;
93
my $domain         = qr/$dot_atom|$domain_literal/;
94

  
95
my $display_name   = $phrase;
96

  
97
=head2 Package Variables
98

  
99
Several regular expressions used in this package are useful to others.
100
For convenience, these variables are declared as package variables that
101
you may access from your program.
102

  
103
These regular expressions conform to the rules specified in RFC 2822.
104

  
105
You can access these variables using the full namespace. If you want
106
short names, define them yourself.
107

  
108
  my $addr_spec = $Email::Address::addr_spec;
109

  
110
=over 4
111

  
112
=item $Email::Address::addr_spec
113

  
114
This regular expression defined what an email address is allowed to
115
look like.
116

  
117
=item $Email::Address::angle_addr
118

  
119
This regular expression defines an C<$addr_spec> wrapped in angle
120
brackets.
121

  
122
=item $Email::Address::name_addr
123

  
124
This regular expression defines what an email address can look like
125
with an optional preceeding display name, also known as the C<phrase>.
126

  
127
=item $Email::Address::mailbox
128

  
129
This is the complete regular expression defining an RFC 2822 emial
130
address with an optional preceeding display name and optional
131
following comment.
132

  
133
=back
134

  
135
=cut
136

  
137
$addr_spec  = qr/$local_part\@$domain/;
138
$angle_addr = qr/$cfws*<$addr_spec>$cfws*/;
139
$name_addr  = qr/$display_name?$angle_addr/;
140
$mailbox    = qr/(?:$name_addr|$addr_spec)$comment*/;
141

  
142
sub _PHRASE   () { 0 }
143
sub _ADDRESS  () { 1 }
144
sub _COMMENT  () { 2 }
145
sub _ORIGINAL () { 3 }
146
sub _IN_CACHE () { 4 }
147

  
148
=head2 Class Methods
149

  
150
=over 4
151

  
152
=item parse
153

  
154
  my @addrs = Email::Address->parse(
155
    q[me@local, Casey <me@local>, "Casey" <me@local> (West)]
156
  );
157

  
158
This method returns a list of C<Email::Address> objects it finds
159
in the input string.
160

  
161
The specification for an email address allows for infinitley
162
nestable comments. That's nice in theory, but a little over done.
163
By default this module allows for two (C<2>) levels of nested
164
comments. If you think you need more, modify the
165
C<$Email::Address::COMMENT_NEST_LEVEL> package variable to allow
166
more.
167

  
168
  $Email::Address::COMMENT_NEST_LEVEL = 10; # I'm deep
169

  
170
The reason for this hardly limiting limitation is simple: efficiency.
171

  
172
Long strings of whitespace can be problematic for this module to parse, a bug
173
which has not yet been adequately addressed.  The default behavior is now to
174
collapse multiple spaces into a single space, which avoids this problem.  To
175
prevent this behavior, set C<$Email::Address::COLLAPSE_SPACES> to zero.  This
176
variable will go away when the bug is resolved properly.
177

  
178
=cut
179

  
180
sub __get_cached_parse {
181
    return if $NOCACHE;
182

  
183
    my ($class, $line) = @_;
184

  
185
    return @{$PARSE_CACHE{$line}} if exists $PARSE_CACHE{$line};
186
    return; 
187
}
188

  
189
sub __cache_parse {
190
    return if $NOCACHE;
191
    
192
    my ($class, $line, $addrs) = @_;
193

  
194
    $PARSE_CACHE{$line} = $addrs;
195
}
196

  
197
sub parse {
198
    my ($class, $line) = @_;
199
    return unless $line;
200

  
201
    $line =~ s/[ \t]+/ /g if $COLLAPSE_SPACES;
202

  
203
    if (my @cached = $class->__get_cached_parse($line)) {
204
        return @cached;
205
    }
206

  
207
    my (@mailboxes) = ($line =~ /$mailbox/go);
208
    my @addrs;
209
    foreach (@mailboxes) {
210
      my $original = $_;
211

  
212
      my @comments = /($comment)/go;
213
      s/$comment//go if @comments;
214

  
215
      my ($user, $host, $com);
216
      ($user, $host) = ($1, $2) if s/<($local_part)\@($domain)>//o;
217
      if (! defined($user) || ! defined($host)) {
218
          s/($local_part)\@($domain)//o;
219
          ($user, $host) = ($1, $2);
220
      }
221

  
222
      my ($phrase)       = /($display_name)/o;
223

  
224
      for ( $phrase, $host, $user, @comments ) {
225
        next unless defined $_;
226
        s/^\s+//;
227
        s/\s+$//;
228
        $_ = undef unless length $_;
229
      }
230

  
231
      my $new_comment = join q{ }, @comments;
232
      push @addrs,
233
        $class->new($phrase, "$user\@$host", $new_comment, $original);
234
      $addrs[-1]->[_IN_CACHE] = [ \$line, $#addrs ]
235
    }
236

  
237
    $class->__cache_parse($line, \@addrs);
238
    return @addrs;
239
}
240

  
241
=pod
242

  
243
=item new
244

  
245
  my $address = Email::Address->new(undef, 'casey@local');
246
  my $address = Email::Address->new('Casey West', 'casey@local');
247
  my $address = Email::Address->new(undef, 'casey@local', '(Casey)');
248

  
249
Constructs and returns a new C<Email::Address> object. Takes four
250
positional arguments: phrase, email, and comment, and original string.
251

  
252
The original string should only really be set using C<parse>.
253

  
254
=cut
255

  
256
sub new { bless [@_[1..4]], $_[0] }
257

  
258
=pod
259

  
260
=item purge_cache
261

  
262
  Email::Address->purge_cache;
263

  
264
One way this module stays fast is with internal caches. Caches live
265
in memory and there is the remote possibility that you will have a
266
memory problem. In the off chance that you think you're one of those
267
people, this class method will empty those caches.
268

  
269
I've loaded over 12000 objects and not encountered a memory problem.
270

  
271
=cut
272

  
273
sub purge_cache {
274
    %NAME_CACHE   = ();
275
    %FORMAT_CACHE = ();
276
    %PARSE_CACHE  = ();
277
}
278

  
279
=item disable_cache
280

  
281
=item enable_cache
282

  
283
  Email::Address->disable_cache if memory_low();
284

  
285
If you'd rather not cache address parses at all, you can disable (and reenable) the Email::Address cache with these methods.  The cache is enabled by default.
286

  
287
=cut
288

  
289
sub disable_cache {
290
  my ($class) = @_;
291
  $class->purge_cache;
292
  $NOCACHE = 1;
293
}
294

  
295
sub enable_cache {
296
  $NOCACHE = undef;
297
}
298

  
299
=pod
300

  
301
=back
302

  
303
=head2 Instance Methods
304

  
305
=over 4
306

  
307
=item phrase
308

  
309
  my $phrase = $address->phrase;
310
  $address->phrase( "Me oh my" );
311

  
312
Accessor and mutator for the phrase portion of an address.
313

  
314
=item address
315

  
316
  my $addr = $address->address;
317
  $addr->address( "me@PROTECTED.com" );
318

  
319
Accessor and mutator for the address portion of an address.
320

  
321
=item comment
322

  
323
  my $comment = $address->comment;
324
  $address->comment( "(Work address)" );
325

  
326
Accessor and mutator for the comment portion of an address.
327

  
328
=item original
329

  
330
  my $orig = $address->original;
331

  
332
Accessor for the original address found when parsing, or passed
333
to C<new>.
334

  
335
=item host
336

  
337
  my $host = $address->host;
338

  
339
Accessor for the host portion of an address's address.
340

  
341
=item user
342

  
343
  my $user = $address->user;
344

  
345
Accessor for the user portion of an address's address.
346

  
347
=cut
348

  
349
BEGIN {
350
  my %_INDEX = (
351
    phrase   => _PHRASE,
352
    address  => _ADDRESS,
353
    comment  => _COMMENT,
354
    original => _ORIGINAL,
355
  );
356

  
357
  for my $method (keys %_INDEX) {
358
    no strict 'refs';
359
    my $index = $_INDEX{ $method };
360
    *$method = sub {
361
      if ($_[1]) {
362
        if ($_[0][_IN_CACHE]) {
363
          my $replicant = bless [ @{$_[0]} ] => ref $_[0];
364
          $PARSE_CACHE{ ${ $_[0][_IN_CACHE][0] } }[ $_[0][_IN_CACHE][1] ] 
365
            = $replicant;
366
          $_[0][_IN_CACHE] = undef;
367
        }
368
        $_[0]->[ $index ] = $_[1];
369
      } else {
370
        $_[0]->[ $index ];
371
      }
372
    };
373
  }
374
}
375

  
376
sub host { ($_[0]->[_ADDRESS] =~ /\@($domain)/o)[0]     }
377
sub user { ($_[0]->[_ADDRESS] =~ /($local_part)\@/o)[0] }
378

  
379
=pod
380

  
381
=item format
382

  
383
  my $printable = $address->format;
384

  
385
Returns a properly formatted RFC 2822 address representing the
386
object.
387

  
388
=cut
389

  
390
sub format {
391
    local $^W = 0; ## no critic
392
    return $FORMAT_CACHE{"@{$_[0]}"} if exists $FORMAT_CACHE{"@{$_[0]}"};
393
    $FORMAT_CACHE{"@{$_[0]}"} = $_[0]->_format;
394
}
395

  
396
sub _format {
397
    my ($self) = @_;
398

  
399
    unless (
400
      defined $self->[_PHRASE] && length $self->[_PHRASE]
401
      ||
402
      defined $self->[_COMMENT] && length $self->[_COMMENT]
403
    ) {
404
        return $self->[_ADDRESS];
405
    }
406

  
407
    my $format = sprintf q{%s <%s> %s},
408
                 $self->_enquoted_phrase, $self->[_ADDRESS], $self->[_COMMENT];
409

  
410
    $format =~ s/^\s+//;
411
    $format =~ s/\s+$//;
412

  
413
    return $format;
414
}
415

  
416
sub _enquoted_phrase {
417
  my ($self) = @_;
418

  
419
  my $phrase = $self->[_PHRASE];
420

  
421
  # if it's encoded -- rjbs, 2007-02-28
422
  return $phrase if $phrase =~ /\A=\?.+\?=\z/;
423

  
424
  $phrase =~ s/\A"(.+)"\z/$1/;
425
  $phrase =~ s/\"/\\"/g;
426

  
427
  return qq{"$phrase"};
428
}
429

  
430
=pod
431

  
432
=item name
433

  
434
  my $name = $address->name;
435

  
436
This method tries very hard to determine the name belonging to the address.
437
First the C<phrase> is checked. If that doesn't work out the C<comment>
438
is looked into. If that still doesn't work out, the C<user> portion of
439
the C<address> is returned.
440

  
441
This method does B<not> try to massage any name it identifies and instead
442
leaves that up to someone else. Who is it to decide if someone wants their
443
name capitalized, or if they're Irish?
444

  
445
=cut
446

  
447
sub name {
448
    local $^W = 0;
449
    return $NAME_CACHE{"@{$_[0]}"} if exists $NAME_CACHE{"@{$_[0]}"};
450
    my ($self) = @_;
451
    my $name = q{};
452
    if ( $name = $self->[_PHRASE] ) {
453
        $name =~ s/^"//;
454
        $name =~ s/"$//;
455
        $name =~ s/($quoted_pair)/substr $1, -1/goe;
456
    } elsif ( $name = $self->[_COMMENT] ) {
457
        $name =~ s/^\(//;
458
        $name =~ s/\)$//;
459
        $name =~ s/($quoted_pair)/substr $1, -1/goe;
460
        $name =~ s/$comment/ /go;
461
    } else {
462
        ($name) = $self->[_ADDRESS] =~ /($local_part)\@/o;
463
    }
464
    $NAME_CACHE{"@{$_[0]}"} = $name;
465
}
466

  
467
=pod
468

  
469
=back
470

  
471
=head2 Overloaded Operators
472

  
473
=over 4
474

  
475
=item stringify
476

  
477
  print "I have your email address, $address.";
478

  
479
Objects stringify to C<format> by default. It's possible that you don't
480
like that idea. Okay, then, you can change it by modifying
481
C<$Email:Address::STRINGIFY>. Please consider modifying this package
482
variable using C<local>. You might step on someone else's toes if you
483
don't.
484

  
485
  {
486
    local $Email::Address::STRINGIFY = 'address';
487
    print "I have your address, $address.";
488
    #   geeknest.com
489
  }
490
  print "I have your address, $address.";
491
  #   "Casey West" <casey@geeknest.com>
492

  
493
=cut
494

  
495
sub as_string {
496
  warn 'altering $Email::Address::STRINGIFY is deprecated; subclass instead'
497
    if $STRINGIFY ne 'format';
498

  
499
  $_[0]->can($STRINGIFY)->($_[0]);
500
}
501

  
502
use overload '""' => 'as_string';
503

  
504
=pod
505

  
506
=back
507

  
508
=cut
509

  
510
1;
511

  
512
__END__
513

  
514
=head2 Did I Mention Fast?
515

  
516
On his 1.8GHz Apple MacBook, rjbs gets these results:
517

  
518
  $ perl -Ilib bench/ea-vs-ma.pl bench/corpus.txt 5 
519
                   Rate  Mail::Address Email::Address
520
  Mail::Address  2.59/s             --           -44%
521
  Email::Address 4.59/s            77%             --
522

  
523
  $ perl -Ilib bench/ea-vs-ma.pl bench/corpus.txt 25
524
                   Rate  Mail::Address Email::Address
525
  Mail::Address  2.58/s             --           -67%
526
  Email::Address 7.84/s           204%             --
527

  
528
  $ perl -Ilib bench/ea-vs-ma.pl bench/corpus.txt 50
529
                   Rate  Mail::Address Email::Address
530
  Mail::Address  2.57/s             --           -70%
531
  Email::Address 8.53/s           232%             --
532

  
533
...unfortunately, a known bug causes a loss of speed the string to parse has
534
certain known characteristics, and disabling cache will also degrade
535
performance.
536

  
537
=head1 PERL EMAIL PROJECT
538

  
539
This module is maintained by the Perl Email Project
540

  
541
L<http://emailproject.perl.org/wiki/Email::Address>
542

  
543
=head1 SEE ALSO
544

  
545
L<Email::Simple>, L<perl>.
546

  
547
=head1 AUTHOR
548

  
549
Originally by Casey West, <F<casey@geeknest.com>>.
550

  
551
Maintained, 2006-2007, Ricardo SIGNES <F<rjbs@cpan.org>>.
552

  
553
=head1 ACKNOWLEDGEMENTS
554

  
555
Thanks to Kevin Riggle and Tatsuhiko Miyagawa for tests for annoying phrase-quoting bugs!
556

  
557
=head1 COPYRIGHT
558

  
559
Copyright (c) 2004 Casey West.  All rights reserved.  This module is free
560
software; you can redistribute it and/or modify it under the same terms as Perl
561
itself.
562

  
563
=cut
564

  

Auch abrufbar als: Unified diff