]> git.p6c8.net - selfforum.git/blob - selfforum-cgi/shared/Mail.pm
8ba56e3971587a162f4e4acd14de1f115faa8ba5
[selfforum.git] / selfforum-cgi / shared / Mail.pm
1 # Mail.pm
2
3 ##############################################
4 # #
5 # Autor: n.d.p. nd@o3media.de #
6 # #
7 # Letze Aenderung: n.d.p. / 2001-01-03 #
8 # #
9 # ========================================== #
10 # #
11 # Funktion: #
12 # ganz simples Formatieren und Senden #
13 # einer Mail im text/plain, qp-Format #
14 # #
15 ##############################################
16
17 use strict;
18
19 package Mail;
20
21 use vars qw($mailbox $mailprog @EXPORT);
22
23 # ===================
24 # Funktionsexport
25 # ===================
26
27 use base qw(Exporter);
28 @EXPORT = qw(is_mail_address send_mail);
29
30 ########################################
31 # EXPORT
32 # sub is_mail_address
33 #
34 # Funktion:
35 # Ueberpruefen der Syntax einer
36 # Email-Adresse
37 #
38 # Rueckgabe
39 # true/false
40 ########################################
41
42 sub is_mail_address ($) {
43 return ($_[0] =~ /$mailbox/);
44 }
45
46 ########################################
47 # EXPORT
48 # sub send_mail
49 #
50 # Funktion:
51 # Senden der Nachricht
52 # ueber open-print-close
53 # $Mail::mailprog enthaelt
54 # den vollstaendigen string fuer
55 # open, dass heisst, es kann
56 # auch ein Dateiname sein.
57 #
58 # Rueckgabe:
59 # true/false
60 ########################################
61
62 sub send_mail {
63 my $param=shift;
64 local *MAIL;
65
66 open MAIL,$mailprog or return 0;
67 print MAIL &as_string ($param);
68 close MAIL and return 1;
69
70 # Hier muss irgendwas schiefgelaufen sein
71 0;
72 }
73
74 ##########################################
75 # PRIVAT
76 # sub as_string
77 #
78 # Funktion:
79 # Bereitstellung der gesamten Mail
80 # als String.
81 #
82 # Rueckgabe:
83 # String
84 ##########################################
85
86 sub as_string {
87 my $param=shift;
88
89 my $header=&header_as_string ($param);
90 my $body=&body_as_string ($param);
91
92 # Rueckgabe
93 "$header\n$body\n";
94 }
95
96 ##########################################
97 # PRIVAT
98 # sub body_as_string
99 #
100 # Funktion:
101 # Bereitstellung des Bodys
102 # als (qp-codierten) String.
103 #
104 # Rueckgabe:
105 # String
106 ##########################################
107
108 sub body_as_string {
109 my $param=shift;
110
111 &encode_qp($param->{body});
112 }
113
114 ##########################################
115 # PRIVAT
116 # sub header_as_string
117 #
118 # Funktion:
119 # Bereitstellung des Headers
120 # als String.
121 #
122 # Rueckgabe:
123 # String
124 ##########################################
125
126 sub header_as_string {
127 my $param=shift;
128
129 my $string="Content-Disposition: inline\n";
130 $string.="MIME-Version: 1.0\n";
131 $string.="Content-Transfer-Encoding: quoted-printable\n";
132 $string.="Content-Type: text/plain\n";
133 $string.="Date: ".&rfc822_date(time)."\n";
134 $string.="From: ".$param->{'from'}."\n";
135 $string.=&get_list('To',$param->{'to'});
136 $string.=&get_list('Cc',$param->{'cc'});
137 $string.=&get_list('Bcc',$param->{'bcc'});
138 $string.="Subject: ".encode_qp($param->{'subject'})."\n";
139
140 # Rueckgabe
141 $string;
142 }
143
144 #######################################
145 # PRIVAT
146 # sub encode_qp
147 #
148 # C&P aus dem Modul MIME::QuotedPrint
149 # Thanx for that
150 #######################################
151
152 sub encode_qp ($)
153 {
154 my $res = shift;
155 $res =~ s/([^ \t\n!-<>-~])/sprintf("=%02X", ord($1))/eg; # rule #2,#3
156 $res =~ s/([ \t]+)$/
157 join('', map { sprintf("=%02X", ord($_)) }
158 split('', $1)
159 )/egm; # rule #3 (encode whitespace at eol)
160
161 # rule #5 (lines must be shorter than 76 chars, but we are not allowed
162 # to break =XX escapes. This makes things complicated :-( )
163 my $brokenlines = "";
164 $brokenlines .= "$1=\n"
165 while $res =~ s/(.*?^[^\n]{73} (?:
166 [^=\n]{2} (?! [^=\n]{0,1} $) # 75 not followed by .?\n
167 |[^=\n] (?! [^=\n]{0,2} $) # 74 not followed by .?.?\n
168 | (?! [^=\n]{0,3} $) # 73 not followed by .?.?.?\n
169 ))//xsm;
170
171 "$brokenlines$res";
172 }
173
174 ##############################################
175 # PRIVAT
176 # sub get_list
177 #
178 # Funktion:
179 # Aufbereitung einer Liste oder eines
180 # Strings fuer den Header (To, Cc, Bcc)
181 #
182 # Rueckgabe:
183 # Ergebnis oder nichts
184 ##############################################
185
186 sub get_list ($$) {
187 my ($start,$list)=splice @_;
188
189 return $start . ': ' . $list . "\n" if (defined $list and not ref $list and length $list);
190
191 return $start . ': ' . join (', ',@$list) . "\n" if (ref $list);
192
193 '';
194 }
195
196 ##############################################
197 # PRIVAT
198 # sub rfc822_date
199 #
200 # Funktion:
201 # Bereitstellung eines RFC-konformen
202 # Datumstrings
203 #
204 # Rueckgabe:
205 # Datumstring
206 ##############################################
207
208 sub rfc822_date ($) {
209 my ($sek, $min, $std, $mtag, $mon, $jahr, $wtag) = gmtime (+shift);
210
211 sprintf ('%s, %02d %s %04d %02d:%02d:%02d GMT',
212 (qw(Sun Mon Tue Wed Thu Fri Sat))[$wtag],
213 $mtag,
214 (qw(Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec))[$mon],
215 $jahr+1900, $std, $min, $sek);
216 }
217
218 ##############################################
219 # Modulinitialisierung
220 # BEGIN
221 #
222 # Funktion:
223 # Bereitstellung des Regexps und des
224 # Mailprogs
225 ##############################################
226
227 BEGIN {
228 # Standard-Mailprogramm
229
230 # Dieser String wird so, wie er ist, an die open-Anweisung geschickt,
231 # -t = tainted(?),der Header (=alles bis zur ersten Leerzeile)
232 # wird nach To:, Cc: und evtl. Bcc: abgesucht.
233 # -oi = damit wird verhindert, dass sendmail, ein Zeile, wo nur ein
234 # Punkt drinsteht, als Mailende erkennt( waere Standard ).
235 # ===================================================================
236
237 $mailprog = '|/usr/lib/sendmail -t -oi';
238
239 # Thanx to J. Friedl for this regex:
240
241 my ($address,$route_addr,$phrase,$addr_spec,$X,$phrase_char,$quoted_str,$comment,$word,$phrase_ctrl,$NonASCII,
242 $CloseBR,$OpenBR,$esc,$route,$domain,$local_part,$Period,$sub_domain,$domain_lit,$domain_ref,$quoted_pair,
243 $dtext,$atom,$qtext,$atom_char,$ctrl,$space,$tab,$CloseParen,$ctext,$Cnested,$OpenParen,$CRlist);
244
245 $esc = '\\\\';
246 $Period = '\.';
247 $space = '\040';
248 $tab = '\t';
249 $OpenBR = '\[';
250 $CloseBR = '\]';
251 $OpenParen = '\(';
252 $CloseParen = '\)';
253 $NonASCII = '\x80-\xff';
254 $ctrl = '\000-\037';
255 $CRlist = '\n\015';
256 $qtext = qq/[^$esc$NonASCII$CRlist\"]/;
257 $dtext = qq/[^$esc$NonASCII$CRlist$OpenBR$CloseBR]/;
258 $quoted_pair = qq< $esc [^$NonASCII] >;
259 $ctext = qq< [^$esc$NonASCII$CRlist()] >;
260 $Cnested = qq< $OpenParen $ctext* (?: $quoted_pair $ctext* )* $CloseParen >;
261 $comment = qq< $OpenParen $ctext* (?: (?: $quoted_pair | $Cnested ) $ctext* )* $CloseParen >;
262 $X = qq< [$space$tab]* (?: $comment [$space$tab]* )* >;
263 $atom_char = qq/[^($space)<>\@,;:\".$esc$OpenBR$CloseBR$ctrl$NonASCII]/;
264 $atom = qq< $atom_char+ (?!$atom_char) >;
265 $quoted_str = qq< \" $qtext * (?: $quoted_pair $qtext * )* \" >;
266 $word = qq< (?: $atom | $quoted_str ) >;
267 $domain_ref = $atom;
268 $domain_lit = qq< $OpenBR (?: $dtext | $quoted_pair )* $CloseBR >;
269 $sub_domain = qq< (?: $domain_ref | $domain_lit ) $X >;
270 $domain = qq< $sub_domain (?: $Period $X $sub_domain )* >;
271 $route = qq< \@ $X $domain (?: , $X \@ $X $domain )* : $X >;
272 $local_part = qq< $word $X (?: $Period $X $word $X )* >;
273 $addr_spec = qq< $local_part \@ $X $domain >;
274 $route_addr = qq[ < $X (?: $route )? $addr_spec > ];
275 $phrase_ctrl = '\000-\010\012-\037';
276 $phrase_char = qq/[^()<>\@,;:\".$esc$OpenBR$CloseBR$NonASCII$phrase_ctrl]/;
277 $phrase = qq< $word $phrase_char * (?: (?: $comment | $quoted_str ) $phrase_char * )* >;
278 $mailbox = qq< $X (?: $addr_spec | $phrase $route_addr ) >;
279 $mailbox = qr ~^$mailbox$~x;
280 }
281
282 # making 'require' happy
283 1;
284
285 #####################
286 # end of Mail
287 #####################

patrick-canterino.de