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