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