xref: /dokuwiki/_test/tests/inc/mailer.test.php (revision 30085ef3769da1a92634254411d688dbb753e762)
1<?php
2
3/**
4 * Extends the mailer class to expose internal variables for testing
5 */
6class TestMailer extends Mailer {
7    public function prop($name){
8        return $this->$name;
9    }
10
11    public function &propRef($name) {
12        return $this->$name;
13    }
14
15    public function prepareHeaders() {
16        return parent::prepareHeaders();
17    }
18
19    public function cleanHeaders() {
20        parent::cleanHeaders();
21    }
22
23}
24
25class mailer_test extends DokuWikiTest {
26
27
28    function test_userheader(){
29        $mail = new TestMailer();
30        $headers = $mail->prop('headers');
31        $this->assertArrayNotHasKey('X-Dokuwiki-User',$headers);
32
33        $_SERVER['REMOTE_USER'] = 'andi';
34        $mail = new TestMailer();
35        $headers = $mail->prop('headers');
36        $this->assertArrayHasKey('X-Dokuwiki-User',$headers);
37    }
38
39    function test_setHeader(){
40        $mail = new TestMailer();
41
42        // check existance of default headers
43        $headers = $mail->prop('headers');
44        $this->assertArrayHasKey('X-Mailer',$headers);
45        $this->assertArrayHasKey('X-Dokuwiki-Title',$headers);
46        $this->assertArrayHasKey('X-Dokuwiki-Server',$headers);
47        $this->assertArrayHasKey('X-Auto-Response-Suppress',$headers);
48        $this->assertArrayHasKey('List-Id',$headers);
49
50        // set a bunch of test headers
51        $mail->setHeader('test-header','bla');
52        $mail->setHeader('to','A valid ASCII name <test@example.com>');
53        $mail->setHeader('from',"Thös ne\needs\x00serious cleaning\$§%.");
54        $mail->setHeader('bad',"Thös ne\needs\x00serious cleaning\$§%.",false);
55        $mail->setHeader("weird\n*+\x00foo.-_@bar?",'now clean');
56
57        // are they set?
58        $headers = $mail->prop('headers');
59        $this->assertArrayHasKey('Test-Header',$headers);
60        $this->assertEquals('bla',$headers['Test-Header']);
61        $this->assertArrayHasKey('To',$headers);
62        $this->assertEquals('A valid ASCII name <test@example.com>',$headers['To']);
63        $this->assertArrayHasKey('From',$headers);
64        $this->assertEquals('Ths neeedsserious cleaning.',$headers['From']);
65        $this->assertArrayHasKey('Bad',$headers);
66        $this->assertEquals("Thös ne\needs\x00serious cleaning\$§%.",$headers['Bad']);
67        $this->assertArrayHasKey('Weird+foo.-_@bar',$headers);
68
69        // unset a header again
70        $mail->setHeader('test-header','');
71        $headers = $mail->prop('headers');
72        $this->assertArrayNotHasKey('Test-Header',$headers);
73    }
74
75    function test_addresses(){
76        $mail = new TestMailer();
77
78        $mail->to('andi@splitbrain.org');
79        $mail->cleanHeaders();
80        $headers = $mail->prop('headers');
81        $this->assertEquals('andi@splitbrain.org', $headers['To']);
82
83        $mail->to('<andi@splitbrain.org>');
84        $mail->cleanHeaders();
85        $headers = $mail->prop('headers');
86        $this->assertEquals('andi@splitbrain.org', $headers['To']);
87
88        $mail->to('Andreas Gohr <andi@splitbrain.org>');
89        $mail->cleanHeaders();
90        $headers = $mail->prop('headers');
91
92        if (isWindows()) { // see FS#652
93            $this->assertEquals('andi@splitbrain.org', $headers['To']);
94        } else {
95            $this->assertEquals('Andreas Gohr <andi@splitbrain.org>', $headers['To']);
96        }
97
98        $mail->to('Andreas Gohr <andi@splitbrain.org> , foo <foo@example.com>');
99        $mail->cleanHeaders();
100        $headers = $mail->prop('headers');
101        if (isWindows()) { // see FS#652
102            $this->assertEquals('andi@splitbrain.org,  foo@example.com', $headers['To']);
103        } else {
104            $this->assertEquals('Andreas Gohr <andi@splitbrain.org>, foo <foo@example.com>', $headers['To']);
105        }
106
107        $mail->to('Möp <moep@example.com> , foo <foo@example.com>');
108        $mail->cleanHeaders();
109        $headers = $mail->prop('headers');
110
111        if (isWindows()) { // see FS#652
112            $this->assertEquals('moep@example.com,  foo@example.com', $headers['To']);
113        } else {
114            $this->assertEquals('=?UTF-8?B?TcO2cA==?= <moep@example.com>, foo <foo@example.com>', $headers['To']);
115        }
116
117        $mail->to(array('Möp <moep@example.com> ',' foo <foo@example.com>'));
118        $mail->cleanHeaders();
119        $headers = $mail->prop('headers');
120        if (isWindows()) { // see FS#652
121            $this->assertEquals('moep@example.com,  foo@example.com', $headers['To']);
122        } else {
123            $this->assertEquals('=?UTF-8?B?TcO2cA==?= <moep@example.com>, foo <foo@example.com>', $headers['To']);
124        }
125
126        $mail->to(array('Beet, L van <lvb@example.com>',' foo <foo@example.com>'));
127        $mail->cleanHeaders();
128        $headers = $mail->prop('headers');
129        if (isWindows()) { // see FS#652
130            $this->assertEquals('lvb@example.com,  foo@example.com', $headers['To']);
131        } else {
132            $this->assertEquals('=?UTF-8?B?QmVldCwgTCB2YW4=?= <lvb@example.com>, foo <foo@example.com>', $headers['To']);
133        }
134
135
136    }
137
138    function test_simplemail(){
139        global $conf;
140        $conf['htmlmail'] = 0;
141
142        $mailbody = 'A test mail in ASCII';
143        $mail = new TestMailer();
144        $mail->to('test@example.com');
145        $mail->setBody($mailbody);
146
147        $dump = $mail->dump();
148
149        // construct the expected mail body text - include the expected dokuwiki signature
150        $replacements = $mail->prop('replacements');
151        $expected_mail_body = chunk_split(base64_encode($mailbody.$replacements['text']['EMAILSIGNATURE']),72,MAILHEADER_EOL);
152
153        $this->assertNotRegexp('/Content-Type: multipart/',$dump);
154        $this->assertRegexp('#Content-Type: text/plain; charset=UTF-8#',$dump);
155        $this->assertRegexp('/'.preg_quote($expected_mail_body,'/').'/',$dump);
156
157        $conf['htmlmail'] = 1;
158    }
159
160    function test_replacements(){
161        $mail = new TestMailer();
162
163        $replacements = array( '@DATE@','@BROWSER@','@IPADDRESS@','@HOSTNAME@','@EMAILSIGNATURE@',
164                               '@TITLE@','@DOKUWIKIURL@','@USER@','@NAME@','@MAIL@');
165        $mail->setBody('A test mail in with replacements '.join(' ',$replacements));
166
167        $text = $mail->prop('text');
168        $html = $mail->prop('html');
169
170        foreach($replacements as $repl){
171            $this->assertNotRegexp("/$repl/",$text,"$repl replacement still in text");
172            $this->assertNotRegexp("/$repl/",$html,"$repl replacement still in html");
173        }
174    }
175
176    /**
177     * @see https://forum.dokuwiki.org/post/35822
178     */
179    function test_emptyBCCorCC() {
180        $mail = new TestMailer();
181        $headers = &$mail->propRef('headers');
182        $headers['Bcc'] = '';
183        $headers['Cc'] = '';
184        $header = $mail->prepareHeaders();
185        $this->assertEquals(0, preg_match('/(^|\n)Bcc: (\n|$)/', $header), 'Bcc found in headers.');
186        $this->assertEquals(0, preg_match('/(^|\n)Cc: (\n|$)/', $header), 'Cc found in headers.');
187    }
188
189    function test_nullTOorCCorBCC() {
190        $mail = new TestMailer();
191        $headers = &$mail->propRef('headers');
192        $headers['Bcc'] = NULL;
193        $headers['Cc'] = NULL;
194        $headers['To'] = NULL;
195        $header = $mail->prepareHeaders();
196        $this->assertEquals(0, preg_match('/(^|\n)Bcc: (\n|$)/', $header), 'Bcc found in headers.');
197        $this->assertEquals(0, preg_match('/(^|\n)Cc: (\n|$)/', $header), 'Cc found in headers.');
198        $this->assertEquals(0, preg_match('/(^|\n)To: (\n|$)/', $header), 'To found in headers.');
199    }
200
201    /**
202     * @group internet
203     */
204    function test_lint(){
205        // prepare a simple multipart message
206        $mail = new TestMailer();
207        $mail->to(array('Möp <moep@example.com> ',' foo <foo@example.com>'));
208        $mail->from('Me <test@example.com>');
209        $mail->subject('This is a töst');
210        $mail->setBody('Hello Wörld,
211
212        please don\'t burn, okay?
213        ');
214        $mail->attachContent('some test data', 'text/plain', 'a text.txt');
215        $msg = $mail->dump();
216        $msglines = explode("\n", $msg);
217
218        //echo $msg;
219
220        // ask message lint if it is okay
221        $html = new HTTPClient();
222        $results = $html->post('https://tools.ietf.org/tools/msglint/msglint', array('msg'=>$msg));
223        if($results === false) {
224            $this->markTestSkipped('no response from validator');
225            return;
226        }
227
228        // parse the result lines
229        $lines = explode("\n", $results);
230        $rows  = count($lines);
231        $i=0;
232        while(trim($lines[$i]) != '-----------' && $i<$rows) $i++; //skip preamble
233        for($i=$i+1; $i<$rows; $i++){
234            $line = trim($lines[$i]);
235            if($line == '-----------') break; //skip appendix
236
237            // get possible continuation of the line
238            while($lines[$i+1][0] == ' '){
239                $line .= ' '.trim($lines[$i+1]);
240                $i++;
241            }
242
243            // check the line for errors
244            if(substr($line,0,5) == 'ERROR' || substr($line,0,7) == 'WARNING'){
245                // ignore some errors
246                if(strpos($line, "missing mandatory header 'return-path'")) continue; #set by MDA
247                if(strpos($line, "bare newline in text body decoded")) continue; #we don't send mail bodies as CRLF, yet
248                if(strpos($line, "last decoded line too long")) continue; #we don't send mail bodies as CRLF, yet
249
250                // get the context in which the error occured
251                $errorin = '';
252                if(preg_match('/line (\d+)$/', $line, $m)){
253                    $errorin .= "\n".$msglines[$m[1] - 1];
254                }
255                if(preg_match('/lines (\d+)-(\d+)$/', $line, $m)){
256                    for($x=$m[1]-1; $x<$m[2]; $x++){
257                        $errorin .= "\n".$msglines[$x];
258                    }
259                }
260
261                // raise the error
262                throw new Exception($line.$errorin);
263            }
264        }
265
266        $this->assertTrue(true); // avoid being marked as risky for having no assertion
267    }
268
269    function test_simplemailsignature() {
270        global $conf;
271        $conf['htmlmail'] = 0;
272
273        $mailbody = 'A test mail in ASCII';
274        $signature = "\n-- \n" . 'This mail was generated by DokuWiki at' . "\n" . DOKU_URL . "\n";
275        $mail = new TestMailer();
276        $mail->to('test@example.com');
277        $mail->setBody($mailbody);
278
279        $dump = $mail->dump();
280
281        // construct the expected mail body text - include the expected dokuwiki signature
282        $expected_mail_body = chunk_split(base64_encode($mailbody . $signature), 72, MAILHEADER_EOL);
283        $this->assertRegexp('/' . preg_quote($expected_mail_body, '/') . '/', $dump);
284
285        $conf['htmlmail'] = 1;
286    }
287
288    function test_htmlmailsignature() {
289        $mailbody_text = 'A test mail in ASCII :)';
290        $mailbody_html = 'A test mail in <strong>html</strong>';
291        $htmlmsg_expected = '<html>
292<head>
293    <title>My Test Wiki</title>
294    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
295</head>
296<body>
297
298A test mail in <strong>html</strong>
299
300<br /><hr />
301<small>This mail was generated by DokuWiki at<br /><a href="' . DOKU_URL . '">' . DOKU_URL . '</a></small>
302</body>
303</html>
304';
305
306        $mail = new TestMailer();
307        $mail->to('test@example.com');
308        $mail->setBody($mailbody_text, null, null, $mailbody_html);
309
310        $dump = $mail->dump();
311
312        // construct the expected mail body text - include the expected dokuwiki signature
313        $expected_mail_body = chunk_split(base64_encode($htmlmsg_expected), 72, MAILHEADER_EOL);
314
315        $this->assertRegexp('/Content-Type: multipart/', $dump);
316        $this->assertRegexp('#Content-Type: text/plain; charset=UTF-8#', $dump);
317        $this->assertRegexp('/' . preg_quote($expected_mail_body, '/') . '/', $dump);
318
319    }
320
321    function test_htmlmailsignaturecustom() {
322        global $lang;
323        $lang['email_signature_html'] = 'Official message from your DokuWiki @DOKUWIKIURL@<br />Created by wonderful mail class <a href="https://www.dokuwiki.org/devel:mail">https://www.dokuwiki.org/devel:mail</a>';
324
325        $mailbody_text = 'A test mail in ASCII :)';
326        $mailbody_html = 'A test mail in <strong>html</strong>';
327        $htmlmsg_expected = '<html>
328<head>
329    <title>My Test Wiki</title>
330    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
331</head>
332<body>
333
334A test mail in <strong>html</strong>
335
336<br /><hr />
337<small>Official message from your DokuWiki <a href="' . DOKU_URL . '">' . DOKU_URL . '</a><br />Created by wonderful mail class <a href="https://www.dokuwiki.org/devel:mail">https://www.dokuwiki.org/devel:mail</a></small>
338</body>
339</html>
340';
341
342        $mail = new TestMailer();
343        $mail->to('test@example.com');
344        $mail->setBody($mailbody_text, null, null, $mailbody_html);
345
346        $dump = $mail->dump();
347
348        // construct the expected mail body text - include the expected dokuwiki signature
349        $replacements = $mail->prop('replacements');
350        $expected_mail_body = chunk_split(base64_encode($htmlmsg_expected), 72, MAILHEADER_EOL);
351
352        $this->assertRegexp('/' . preg_quote($expected_mail_body, '/') . '/', $dump);
353
354    }
355}
356//Setup VIM: ex: et ts=4 :
357