1<?php 2 3use dokuwiki\HTTPClient\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