squirrelmail-webmail  1.4.22
About: SquirrelMail is a standards-based webmail package with strong MIME support, address books, and folder manipulation (written in PHP4).
  Fossies Dox: squirrelmail-webmail-1.4.22.tar.gz  ("inofficial" and yet experimental doxygen-generated source code documentation)  

Deliver.class.php
Go to the documentation of this file.
1 <?php
2 
29 class Deliver {
30 
75  function mail(&$message, $stream=false, $reply_id=0, $reply_ent_id=0,
76  $imap_stream=NULL, $extra=NULL) {
77 
78  $rfc822_header = &$message->rfc822_header;
79 
80  if (count($message->entities)) {
81  $boundary = $this->mimeBoundary();
82  $rfc822_header->content_type->properties['boundary']='"'.$boundary.'"';
83  } else {
84  $boundary='';
85  }
86  $raw_length = 0;
87 
88 
89  // calculate reply header if needed
90  //
91  if ($reply_id) {
94 
95  // try our best to use an existing IMAP handle
96  //
97  $close_imap_stream = FALSE;
98  if (is_resource($imap_stream)) {
99  $my_imap_stream = $imap_stream;
100 
101  } else if (is_resource($imapConnection)) {
102  $my_imap_stream = $imapConnection;
103 
104  } else {
105  $close_imap_stream = TRUE;
106  $my_imap_stream = sqimap_login($username, $key,
108  }
109 
110  sqimap_mailbox_select($my_imap_stream, $mailbox);
111  $reply_message = sqimap_get_message($my_imap_stream, $reply_id, $mailbox);
112 
113  if ($close_imap_stream) {
114  sqimap_logout($my_imap_stream);
115  }
116 
117  if ($reply_ent_id) {
118  /* redefine the messsage in case of message/rfc822 */
119  $reply_message = $message->getEntity($reply_ent_id);
120  /* message is an entity which contains the envelope and type0=message
121  * and type1=rfc822. The actual entities are childs from
122  * $reply_message->entities[0]. That's where the encoding and is located
123  */
124 
125  $orig_header = $reply_message->rfc822_header; /* here is the envelope located */
126 
127  } else {
128  $orig_header = $reply_message->rfc822_header;
129  }
130  $message->reply_rfc822_header = $orig_header;
131  }
132 
133 
134  $reply_rfc822_header = (isset($message->reply_rfc822_header)
135  ? $message->reply_rfc822_header : '');
136  $header = $this->prepareRFC822_Header($rfc822_header, $reply_rfc822_header, $raw_length);
137 
138  $this->send_mail($message, $header, $boundary, $stream, $raw_length, $extra);
139 
140  return $raw_length;
141  }
142 
167  function send_mail($message, $header, $boundary, $stream=false,
168  &$raw_length, $extra=NULL) {
169 
170  if ($stream) {
171  $this->preWriteToStream($header);
172  $this->writeToStream($stream, $header);
173  }
174  $this->writeBody($message, $stream, $raw_length, $boundary);
175  }
176 
196  function writeBody($message, $stream, &$length_raw, $boundary='') {
197  // calculate boundary in case of multidimensional mime structures
198  if ($boundary && $message->entity_id && count($message->entities)) {
199  if (strpos($boundary,'_part_')) {
200  $boundary = substr($boundary,0,strpos($boundary,'_part_'));
201 
202  // the next four lines use strrev to reverse any nested boundaries
203  // because RFC 2046 (5.1.1) says that if a line starts with the outer
204  // boundary string (doesn't matter what the line ends with), that
205  // can be considered a match for the outer boundary; thus the nested
206  // boundary needs to be unique from the outer one
207  //
208  } else if (strpos($boundary,'_trap_')) {
209  $boundary = substr(strrev($boundary),0,strpos(strrev($boundary),'_part_'));
210  }
211  $boundary_new = strrev($boundary . '_part_'.$message->entity_id);
212  } else {
213  $boundary_new = $boundary;
214  }
215  if ($boundary && !$message->rfc822_header) {
216  $s = '--'.$boundary."\r\n";
217  $s .= $this->prepareMIME_Header($message, $boundary_new);
218  $length_raw += strlen($s);
219  if ($stream) {
220  $this->preWriteToStream($s);
221  $this->writeToStream($stream, $s);
222  }
223  }
224  $this->writeBodyPart($message, $stream, $length_raw);
225 
226  $last = false;
227  for ($i=0, $entCount=count($message->entities);$i<$entCount;$i++) {
228  $msg = $this->writeBody($message->entities[$i], $stream, $length_raw, $boundary_new);
229  if ($i == $entCount-1) $last = true;
230  }
231  if ($boundary && $last) {
232  $s = "--".$boundary_new."--\r\n\r\n";
233  $length_raw += strlen($s);
234  if ($stream) {
235  $this->preWriteToStream($s);
236  $this->writeToStream($stream, $s);
237  }
238  }
239  }
240 
258  function writeBodyPart($message, $stream, &$length) {
259  if ($message->mime_header) {
260  $type0 = $message->mime_header->type0;
261  } else {
262  $type0 = $message->rfc822_header->content_type->type0;
263  }
264 
265  $body_part_trailing = $last = '';
266  switch ($type0)
267  {
268  case 'text':
269  case 'message':
270  if ($message->body_part) {
271  $body_part = $message->body_part;
272  // remove NUL characters
273  $body_part = str_replace("\0",'',$body_part);
274  $length += $this->clean_crlf($body_part);
275  if ($stream) {
276  $this->preWriteToStream($body_part);
277  $this->writeToStream($stream, $body_part);
278  }
279  $last = $body_part;
280  } elseif ($message->att_local_name) {
281  global $username, $attachment_dir;
282  $hashed_attachment_dir = getHashedDir($username, $attachment_dir);
283  $filename = $message->att_local_name;
284 
285  // inspect attached file for lines longer than allowed by RFC,
286  // in which case we'll be using base64 encoding (so we can split
287  // the lines up without corrupting them) instead of 8bit unencoded...
288  // (see RFC 2822/2.1.1)
289  //
290  // using 990 because someone somewhere is folding lines at
291  // 990 instead of 998 and I'm too lazy to find who it is
292  //
293  $file_has_long_lines = file_has_long_lines($hashed_attachment_dir
294  . '/' . $filename, 990);
295 
296  $file = fopen ($hashed_attachment_dir . '/' . $filename, 'rb');
297 
298  // long lines were found, need to use base64 encoding
299  //
300  if ($file_has_long_lines) {
301  while ($tmp = fread($file, 570)) {
302  $body_part = chunk_split(base64_encode($tmp));
303  // Up to 4.3.10 chunk_split always appends a newline,
304  // while in 4.3.11 it doesn't if the string to split
305  // is shorter than the chunk length.
306  if( substr($body_part, -1 , 1 ) != "\n" )
307  $body_part .= "\n";
308  $length += $this->clean_crlf($body_part);
309  if ($stream) {
310  $this->writeToStream($stream, $body_part);
311  }
312  }
313  }
314 
315  // no excessively long lines - normal 8bit
316  //
317  else {
318  while ($body_part = fgets($file, 4096)) {
319  $length += $this->clean_crlf($body_part);
320  if ($stream) {
321  $this->preWriteToStream($body_part);
322  $this->writeToStream($stream, $body_part);
323  }
324  $last = $body_part;
325  }
326  }
327 
328  fclose($file);
329  }
330  break;
331  default:
332  if ($message->body_part) {
333  $body_part = $message->body_part;
334  $length += $this->clean_crlf($body_part);
335  if ($stream) {
336  $this->writeToStream($stream, $body_part);
337  }
338  } elseif ($message->att_local_name) {
339  global $username, $attachment_dir;
340  $hashed_attachment_dir = getHashedDir($username, $attachment_dir);
341  $filename = $message->att_local_name;
342  $file = fopen ($hashed_attachment_dir . '/' . $filename, 'rb');
343 
344  while ($tmp = fread($file, 570)) {
345  $body_part = chunk_split(base64_encode($tmp));
346  // Up to 4.3.10 chunk_split always appends a newline,
347  // while in 4.3.11 it doesn't if the string to split
348  // is shorter than the chunk length.
349  if( substr($body_part, -1 , 1 ) != "\n" )
350  $body_part .= "\n";
351  $length += $this->clean_crlf($body_part);
352  if ($stream) {
353  $this->writeToStream($stream, $body_part);
354  }
355  }
356  fclose($file);
357  }
358  break;
359  }
360  $body_part_trailing = '';
361  if ($last && substr($last,-1) != "\n") {
362  $body_part_trailing = "\r\n";
363  }
364  if ($body_part_trailing) {
365  $length += strlen($body_part_trailing);
366  if ($stream) {
367  $this->preWriteToStream($body_part_trailing);
368  $this->writeToStream($stream, $body_part_trailing);
369  }
370  }
371  }
372 
383  function clean_crlf(&$s) {
384  $s = str_replace("\r\n", "\n", $s);
385  $s = str_replace("\r", "\n", $s);
386  $s = str_replace("\n", "\r\n", $s);
387  return strlen($s);
388  }
389 
400  function strip_crlf(&$s) {
401  $s = str_replace("\r\n ", '', $s);
402  $s = str_replace("\r", '', $s);
403  $s = str_replace("\n", '', $s);
404  }
405 
416  function preWriteToStream(&$s) {
417  }
418 
428  fputs($stream, $data);
429  }
430 
445  function initStream($message, $length=0, $host='', $port='', $user='', $pass='') {
446  return $stream;
447  }
448 
456  function getBCC() {
457  return false;
458  }
459 
468  function prepareMIME_Header($message, $boundary) {
469  $mime_header = $message->mime_header;
470  $rn="\r\n";
471  $header = array();
472 
473  $contenttype = 'Content-Type: '. $mime_header->type0 .'/'.
474  $mime_header->type1;
475  if (count($message->entities)) {
476  $contenttype .= ';' . 'boundary="'.$boundary.'"';
477  }
478  if (isset($mime_header->parameters['name'])) {
479  $contenttype .= '; name="'.
480  encodeHeader($mime_header->parameters['name']). '"';
481  }
482  if (isset($mime_header->parameters['charset'])) {
483  $charset = $mime_header->parameters['charset'];
484  $contenttype .= '; charset="'.
485  encodeHeader($charset). '"';
486  }
487 
488  $header[] = $contenttype . $rn;
489  if ($mime_header->description) {
490  $header[] = 'Content-Description: ' . $mime_header->description . $rn;
491  }
492  if ($mime_header->encoding) {
493  $encoding = $mime_header->encoding;
494  $header[] = 'Content-Transfer-Encoding: ' . $mime_header->encoding . $rn;
495  } else {
496 
497  // inspect attached file for lines longer than allowed by RFC,
498  // in which case we'll be using base64 encoding (so we can split
499  // the lines up without corrupting them) instead of 8bit unencoded...
500  // (see RFC 2822/2.1.1)
501  //
502  if (!empty($message->att_local_name)) { // is this redundant? I have no idea
503  global $username, $attachment_dir;
504  $hashed_attachment_dir = getHashedDir($username, $attachment_dir);
505  $filename = $hashed_attachment_dir . '/' . $message->att_local_name;
506 
507  // using 990 because someone somewhere is folding lines at
508  // 990 instead of 998 and I'm too lazy to find who it is
509  //
510  $file_has_long_lines = file_has_long_lines($filename, 990);
511  } else
512  $file_has_long_lines = FALSE;
513 
514  if ($mime_header->type0 == 'multipart' || $mime_header->type0 == 'alternative') {
515  /* no-op; no encoding needed */
516  } else if (($mime_header->type0 == 'text' || $mime_header->type0 == 'message')
517  && !$file_has_long_lines) {
518  $header[] = 'Content-Transfer-Encoding: 8bit' . $rn;
519  } else {
520  $header[] = 'Content-Transfer-Encoding: base64' . $rn;
521  }
522  }
523  if ($mime_header->id) {
524  $header[] = 'Content-ID: ' . $mime_header->id . $rn;
525  }
526  if ($mime_header->disposition) {
527  $disposition = $mime_header->disposition;
528  $contentdisp = 'Content-Disposition: ' . $disposition->name;
529  if ($disposition->getProperty('filename')) {
530  $contentdisp .= '; filename="'.
531  encodeHeader($disposition->getProperty('filename')). '"';
532  }
533  $header[] = $contentdisp . $rn;
534  }
535  if ($mime_header->md5) {
536  $header[] = 'Content-MD5: ' . $mime_header->md5 . $rn;
537  }
538  if ($mime_header->language) {
539  $header[] = 'Content-Language: ' . $mime_header->language . $rn;
540  }
541 
542  $cnt = count($header);
543  $hdr_s = '';
544  for ($i = 0 ; $i < $cnt ; $i++) {
545  $hdr_s .= $this->foldLine($header[$i]);
546  }
547  $header = $hdr_s;
548  $header .= $rn; /* One blank line to separate mimeheader and body-entity */
549  return $header;
550  }
551 
565  function prepareRFC822_Header(&$rfc822_header, $reply_rfc822_header, &$raw_length) {
567 
568  if (! isset($hide_auth_header)) $hide_auth_header=false;
569 
570  /* if server var SERVER_NAME not available, use $domain */
571  if(!sqGetGlobalVar('SERVER_NAME', $SERVER_NAME, SQ_SERVER)) {
572  $SERVER_NAME = $domain;
573  }
574 
575  sqGetGlobalVar('REMOTE_ADDR', $REMOTE_ADDR, SQ_SERVER);
576  sqGetGlobalVar('REMOTE_PORT', $REMOTE_PORT, SQ_SERVER);
577  sqGetGlobalVar('REMOTE_HOST', $REMOTE_HOST, SQ_SERVER);
578  sqGetGlobalVar('HTTP_VIA', $HTTP_VIA, SQ_SERVER);
579  sqGetGlobalVar('HTTP_X_FORWARDED_FOR', $HTTP_X_FORWARDED_FOR, SQ_SERVER);
580 
581  $rn = "\r\n";
582 
583  /* This creates an RFC 822 date */
584  $date = date('D, j M Y H:i:s ', time()) . $this->timezone();
585 
586  /* Create a message-id */
587  $message_id = 'MESSAGE ID GENERATION ERROR! PLEASE CONTACT SQUIRRELMAIL DEVELOPERS';
588  if (empty($rfc822_header->message_id)) {
589  $message_id = '<'
590  . md5(GenerateRandomString(16, '', 7) . uniqid(mt_rand(),true))
591  . '.squirrel@' . $SERVER_NAME .'>';
592  }
593 
594  /* Make an RFC822 Received: line */
595  if (isset($REMOTE_HOST)) {
596  $received_from = "$REMOTE_HOST ([$REMOTE_ADDR])";
597  } else {
598  $received_from = $REMOTE_ADDR;
599  }
600  if (isset($HTTP_VIA) || isset ($HTTP_X_FORWARDED_FOR)) {
601  if (!isset($HTTP_X_FORWARDED_FOR) || $HTTP_X_FORWARDED_FOR == '') {
602  $HTTP_X_FORWARDED_FOR = 'unknown';
603  }
604  $received_from .= " (proxying for $HTTP_X_FORWARDED_FOR)";
605  }
606  $header = array();
607 
624  $show_sm_header = ( defined('hide_squirrelmail_header') ? ! hide_squirrelmail_header : 1 );
625 
626  // FIXME: The following headers may generate slightly differently between the message sent to the destination and that stored in the Sent folder because this code will be called before both actions. This is not necessarily a big problem, but other headers such as Message-ID and Date are preserved between both actions
627  if ( $show_sm_header ) {
628  if (isset($encode_header_key) &&
629  trim($encode_header_key)!='') {
630  // use encoded headers, if encryption key is set and not empty
631  $header[] = 'X-Squirrel-UserHash: '.OneTimePadEncrypt($username,base64_encode($encode_header_key)).$rn;
632  $header[] = 'X-Squirrel-FromHash: '.OneTimePadEncrypt($this->ip2hex($REMOTE_ADDR),base64_encode($encode_header_key)).$rn;
633  if (isset($HTTP_X_FORWARDED_FOR))
634  $header[] = 'X-Squirrel-ProxyHash:'.OneTimePadEncrypt($this->ip2hex($HTTP_X_FORWARDED_FOR),base64_encode($encode_header_key)).$rn;
635  } else {
636  // use default received headers
637  $header[] = "Received: from $received_from" . $rn;
639  $header[] = " (SquirrelMail authenticated user $username)" . $rn;
640  $header[] = " by $SERVER_NAME with HTTP;" . $rn;
641  $header[] = " $date" . $rn;
642  }
643  }
644 
645  /* Insert the rest of the header fields */
646 
647  if (!empty($rfc822_header->message_id)) {
648  $header[] = 'Message-ID: '. $rfc822_header->message_id . $rn;
649  } else {
650  $header[] = 'Message-ID: '. $message_id . $rn;
651  $rfc822_header->message_id = $message_id;
652  }
653 
654  if (is_object($reply_rfc822_header) &&
655  isset($reply_rfc822_header->message_id) &&
656  $reply_rfc822_header->message_id) {
657  //if ($reply_rfc822_header->message_id) {
658  $rep_message_id = $reply_rfc822_header->message_id;
659  $header[] = 'In-Reply-To: '.$rep_message_id . $rn;
660  $rfc822_header->in_reply_to = $rep_message_id;
661  $references = $this->calculate_references($reply_rfc822_header);
662  $header[] = 'References: '.$references . $rn;
663  $rfc822_header->references = $references;
664  }
665 
666  if (!empty($rfc822_header->date) && $rfc822_header->date != -1) {
667  $header[] = 'Date: '. $rfc822_header->date . $rn;
668  } else {
669  $header[] = "Date: $date" . $rn;
670  $rfc822_header->date = $date;
671  }
672 
673  $header[] = 'Subject: '.encodeHeader($rfc822_header->subject) . $rn;
674 
675  // folding address list [From|To|Cc|Bcc] happens by using ",$rn<space>"
676  // as delimiter
677  // Do not use foldLine for that.
678 
679  $header[] = 'From: '. $rfc822_header->getAddr_s('from',",$rn ",true) . $rn;
680 
681  // RFC2822 if from contains more then 1 address
682  if (count($rfc822_header->from) > 1) {
683  $header[] = 'Sender: '. $rfc822_header->getAddr_s('sender',',',true) . $rn;
684  }
685  if (count($rfc822_header->to)) {
686  $header[] = 'To: '. $rfc822_header->getAddr_s('to',",$rn ",true) . $rn;
687  }
688  if (count($rfc822_header->cc)) {
689  $header[] = 'Cc: '. $rfc822_header->getAddr_s('cc',",$rn ",true) . $rn;
690  }
691  if (count($rfc822_header->reply_to)) {
692  $header[] = 'Reply-To: '. $rfc822_header->getAddr_s('reply_to',',',true) . $rn;
693  }
694  /* Sendmail should return true. Default = false */
695  $bcc = $this->getBcc();
696  if (count($rfc822_header->bcc)) {
697  $s = 'Bcc: '. $rfc822_header->getAddr_s('bcc',",$rn ",true) . $rn;
698  if (!$bcc) {
699  $raw_length += strlen($s);
700  } else {
701  $header[] = $s;
702  }
703  }
704  /* Identify SquirrelMail */
705  $header[] = 'User-Agent: SquirrelMail/' . $version . $rn;
706  /* Do the MIME-stuff */
707  $header[] = 'MIME-Version: 1.0' . $rn;
708  $contenttype = 'Content-Type: '. $rfc822_header->content_type->type0 .'/'.
709  $rfc822_header->content_type->type1;
710  if (count($rfc822_header->content_type->properties)) {
711  foreach ($rfc822_header->content_type->properties as $k => $v) {
712  if ($k && $v) {
713  $contenttype .= ';' .$k.'='.$v;
714  }
715  }
716  }
717  $header[] = $contenttype . $rn;
718  if ($encoding = $rfc822_header->encoding) {
719  $header[] = 'Content-Transfer-Encoding: ' . $encoding . $rn;
720  }
721  if ($rfc822_header->dnt) {
722  $dnt = $rfc822_header->getAddr_s('dnt');
723  /* Pegasus Mail */
724  $header[] = 'X-Confirm-Reading-To: '.$dnt. $rn;
725  /* RFC 2298 */
726  $header[] = 'Disposition-Notification-To: '.$dnt. $rn;
727  }
728  if ($rfc822_header->priority) {
729  switch($rfc822_header->priority)
730  {
731  case 1:
732  $header[] = 'X-Priority: 1 (Highest)'.$rn;
733  $header[] = 'Importance: High'. $rn; break;
734  case 3:
735  $header[] = 'X-Priority: 3 (Normal)'.$rn;
736  $header[] = 'Importance: Normal'. $rn; break;
737  case 5:
738  $header[] = 'X-Priority: 5 (Lowest)'.$rn;
739  $header[] = 'Importance: Low'. $rn; break;
740  default: break;
741  }
742  }
743  /* Insert headers from the $more_headers array */
744  if(count($rfc822_header->more_headers)) {
745  reset($rfc822_header->more_headers);
746  foreach ($rfc822_header->more_headers as $k => $v) {
747  $header[] = $k.': '.$v .$rn;
748  }
749  }
750  $cnt = count($header);
751  $hdr_s = '';
752 
753  for ($i = 0 ; $i < $cnt ; $i++) {
754  $sKey = substr($header[$i],0,strpos($header[$i],':'));
755  switch ($sKey)
756  {
757  case 'Message-ID':
758  case 'In-Reply_To':
759  $hdr_s .= $header[$i];
760  break;
761  case 'References':
762  $sRefs = substr($header[$i],12);
763  $aRefs = explode(' ',$sRefs);
764  $sLine = 'References:';
765  foreach ($aRefs as $sReference) {
766  if ( trim($sReference) == '' ) {
767  /* Don't add spaces. */
768  } elseif (strlen($sLine)+strlen($sReference) >76) {
769  $hdr_s .= $sLine;
770  $sLine = $rn . ' ' . $sReference;
771  } else {
772  $sLine .= ' '. $sReference;
773  }
774  }
775  $hdr_s .= $sLine;
776  break;
777  case 'To':
778  case 'Cc':
779  case 'Bcc':
780  case 'From':
781  $hdr_s .= $header[$i];
782  break;
783  default: $hdr_s .= $this->foldLine($header[$i]); break;
784  }
785  }
786  $header = $hdr_s;
787  $header .= $rn; /* One blank line to separate header and body */
788  $raw_length += strlen($header);
789  return $header;
790  }
791 
826  function foldLine($header, $soft_wrap=78, $indent='', $hard_wrap=998) {
827 
828  // the "hard" token list can be altered if desired,
829  // for example, by adding ":"
830  // (in the future, we can take optional arguments
831  // for overriding or adding elements to the "hard"
832  // token list if we want to get fancy)
833  //
834  // the order of these is significant - preferred
835  // fold points should be listed first
836  //
837  // it is advised that the "=" always come first
838  // since it also finds encoded words, thus if it
839  // comes after some other token that happens to
840  // fall within the encoded word, the encoded word
841  // could be inadvertently broken in half, which
842  // is not allowable per RFC
843  //
844  $hard_break_tokens = array(
845  '=', // includes encoded word detection
846  ',',
847  ';',
848  );
849 
850  // the order of these is significant too
851  //
852  $whitespace = array(
853  ' ',
854  "\t",
855  );
856 
857  $CRLF = "\r\n";
858 
859  $folded_header = '';
860 
861  // if using an indent string, reduce wrap limits by its size
862  //
863  if (!empty($indent)) {
864  $soft_wrap -= strlen($indent);
865  $hard_wrap -= strlen($indent);
866  }
867 
868  while (strlen($header) > $soft_wrap) {
869 
870  $soft_wrapped_line = substr($header, 0, $soft_wrap);
871 
872  // look for a token as close to the end of the soft wrap limit as possible
873  //
874  foreach ($whitespace as $token) {
875 
876  // note that this if statement also fails when $pos === 0,
877  // which is intended, since blank lines are not allowed
878  //
879  if ($pos = strrpos($soft_wrapped_line, $token))
880  {
881  $new_fold = substr($header, 0, $pos);
882 
883  // make sure proposed fold doesn't create a blank line
884  //
885  if (!trim($new_fold)) continue;
886 
887  // with whitespace breaks, we fold BEFORE the token
888  //
889  $folded_header .= $new_fold . $CRLF . $indent;
890  $header = substr($header, $pos);
891 
892  // ready for next while() iteration
893  //
894  continue 2;
895 
896  }
897 
898  }
899 
900  // we were unable to find a wrapping point within the soft
901  // wrap limit, so now we'll try to find the first possible
902  // soft wrap point within the hard wrap limit
903  //
904  $hard_wrapped_line = substr($header, 0, $hard_wrap);
905 
906  // look for a *SOFT* token as close to the
907  // beginning of the hard wrap limit as possible
908  //
909  foreach ($whitespace as $token) {
910 
911  // use while loop instead of if block because it
912  // is possible we don't want the first one we find
913  //
914  $pos = $soft_wrap - 1; // -1 is corrected by +1 on next line
915  while ($pos = strpos($hard_wrapped_line, $token, $pos + 1))
916  {
917 
918  $new_fold = substr($header, 0, $pos);
919 
920  // make sure proposed fold doesn't create a blank line
921  //
922  if (!trim($new_fold)) continue;
923 
924  // with whitespace breaks, we fold BEFORE the token
925  //
926  $folded_header .= $new_fold . $CRLF . $indent;
927  $header = substr($header, $pos);
928 
929  // ready for next outter while() iteration
930  //
931  continue 3;
932 
933  }
934 
935  }
936 
937  // we were still unable to find a soft wrapping point within
938  // both the soft and hard wrap limits, so if the length of
939  // what is left is no more than the hard wrap limit, we'll
940  // simply take the whole thing
941  //
942  if (strlen($header) <= strlen($hard_wrapped_line))
943  break;
944 
945  // otherwise, we can't quit yet - look for a "hard" token
946  // as close to the end of the hard wrap limit as possible
947  //
948  foreach ($hard_break_tokens as $token) {
949 
950  // note that this if statement also fails when $pos === 0,
951  // which is intended, since blank lines are not allowed
952  //
953  if ($pos = strrpos($hard_wrapped_line, $token))
954  {
955 
956  // if we found a "=" token, we must determine whether,
957  // if it is part of an encoded word, it is the beginning
958  // or middle of one, where we need to readjust $pos a bit
959  //
960  if ($token == '=') {
961 
962  // if we found the beginning of an encoded word,
963  // we want to break BEFORE the token
964  //
965  if (preg_match('/^(=\?([^?]*)\?(Q|B)\?([^?]*)\?=)/i',
966  substr($header, $pos))) {
967  $pos--;
968  }
969 
970  // check if we found this token in the *middle*
971  // of an encoded word, in which case we have to
972  // ignore it, pushing back to the token that
973  // starts the encoded word instead
974  //
975  // of course, this is only possible if there is
976  // more content after the next hard wrap
977  //
978  // then look for the end of an encoded word in
979  // the next part (past the next hard wrap)
980  //
981  // then see if it is in fact part of a legitimate
982  // encoded word
983  //
984  else if (strlen($header) > $hard_wrap
985  && ($end_pos = strpos(substr($header, $hard_wrap), '?=')) !== FALSE
986  && preg_match('/(=\?([^?]*)\?(Q|B)\?([^?]*)\?=)$/i',
987  substr($header, 0, $hard_wrap + $end_pos + 2),
988  $matches)) {
989 
990  $pos = $hard_wrap + $end_pos + 2 - strlen($matches[1]) - 1;
991 
992  }
993 
994  }
995 
996  // $pos could have been changed; make sure it's
997  // not at the beginning of the line, as blank
998  // lines are not allowed
999  //
1000  if ($pos === 0) continue;
1001 
1002  // we are dealing with a simple token break...
1003  //
1004  // for non-whitespace breaks, we fold AFTER the token
1005  // and add a space after the fold if not immediately
1006  // followed by a whitespace character in the next part
1007  //
1008  $folded_header .= substr($header, 0, $pos + 1) . $CRLF;
1009 
1010  // don't go beyond end of $header, though
1011  //
1012  if (strlen($header) > $pos + 1) {
1013  $header = substr($header, $pos + 1);
1014  if (!in_array($header{0}, $whitespace))
1015  $header = ' ' . $indent . $header;
1016  } else {
1017  $header = '';
1018  }
1019 
1020  // ready for next while() iteration
1021  //
1022  continue 2;
1023 
1024  }
1025 
1026  }
1027 
1028  // finally, we just couldn't find anything to fold on, so we
1029  // have to just cut it off at the hard limit
1030  //
1031  $folded_header .= $hard_wrapped_line . $CRLF;
1032 
1033  // is there more?
1034  //
1035  if (strlen($header) > strlen($hard_wrapped_line)) {
1036  $header = substr($header, strlen($hard_wrapped_line));
1037  if (!in_array($header{0}, $whitespace))
1038  $header = ' ' . $indent . $header;
1039  } else {
1040  $header = '';
1041  }
1042 
1043  }
1044 
1045 
1046  // add any left-overs
1047  //
1048  $folded_header .= $header;
1049 
1050 
1051  // make sure it ends with a CRLF
1052  //
1053  if (substr($folded_header, -2) != $CRLF) $folded_header .= $CRLF;
1054 
1055 
1056  return $folded_header;
1057  }
1058 
1067  function mimeBoundary () {
1068  static $mimeBoundaryString;
1069 
1070  if ( !isset( $mimeBoundaryString ) ||
1071  $mimeBoundaryString == '') {
1072  $mimeBoundaryString = '----=_' . date( 'YmdHis' ) . '_' .
1073  mt_rand( 10000, 99999 );
1074  }
1075  return $mimeBoundaryString;
1076  }
1077 
1083  function timezone () {
1084  global $invert_time, $show_timezone_name;
1085 
1086  $diff_second = date('Z');
1087  if ($invert_time) {
1088  $diff_second = - $diff_second;
1089  }
1090  if ($diff_second > 0) {
1091  $sign = '+';
1092  } else {
1093  $sign = '-';
1094  }
1095  $diff_second = abs($diff_second);
1096  $diff_hour = floor ($diff_second / 3600);
1097  $diff_minute = floor (($diff_second-3600*$diff_hour) / 60);
1098 
1099  // If an administrator wants to add the timezone name to the
1100  // end of the date header, they can set $show_timezone_name
1101  // to boolean TRUE in config/config_local.php, but that is
1102  // NOT RFC-822 compliant (see section 5.1). Moreover, some
1103  // Windows users reported that strftime('%Z') was returning
1104  // the full zone name (not the abbreviation) which in some
1105  // cases included 8-bit characters (not allowed as is in headers).
1106  // The PHP manual actually does NOT promise what %Z will return
1107  // for strftime!: "The time zone offset/abbreviation option NOT
1108  // given by %z (depends on operating system)"
1109  //
1110  if ($show_timezone_name) {
1111  $zonename = '('.strftime('%Z').')';
1112  $result = sprintf ("%s%02d%02d %s", $sign, $diff_hour, $diff_minute, $zonename);
1113  } else {
1114  $result = sprintf ("%s%02d%02d", $sign, $diff_hour, $diff_minute);
1115  }
1116  return ($result);
1117  }
1118 
1130  function calculate_references($hdr) {
1131  $aReferences = preg_split('/\s+/', $hdr->references);
1132  $message_id = $hdr->message_id;
1133  $in_reply_to = $hdr->in_reply_to;
1134 
1135  // if References already exists, add the current message ID at the end.
1136  // no References exists; if we know a IRT, add that aswell
1137  if (count($aReferences) == 0 && $in_reply_to) {
1138  $aReferences[] = $in_reply_to;
1139  }
1140  $aReferences[] = $message_id;
1141 
1142  // sanitize the array: trim whitespace, remove dupes
1143  array_walk($aReferences, 'sq_trim_value');
1144  $aReferences = array_unique($aReferences);
1145 
1146  while ( count($aReferences) > 4 && strlen(implode(' ', $aReferences)) >= 986 ) {
1147  $aReferences = array_merge(array_slice($aReferences,0,1),array_slice($aReferences,2));
1148  }
1149  return implode(' ', $aReferences);
1150  }
1151 
1166  function ip2hex($string) {
1167  if (preg_match("/^(\d+)\.(\d+)\.(\d+)\.(\d+)$/",$string,$match)) {
1168  // ipv4 address
1169  $ret = str_pad(dechex($match[1]),2,'0',STR_PAD_LEFT)
1170  . str_pad(dechex($match[2]),2,'0',STR_PAD_LEFT)
1171  . str_pad(dechex($match[3]),2,'0',STR_PAD_LEFT)
1172  . str_pad(dechex($match[4]),2,'0',STR_PAD_LEFT);
1173  } elseif (preg_match("/^([0-9a-h]+)\:([0-9a-h]+)\:([0-9a-h]+)\:([0-9a-h]+)\:([0-9a-h]+)\:([0-9a-h]+)\:([0-9a-h]+)\:([0-9a-h]+)$/i",$string,$match)) {
1174  // full ipv6 address
1175  $ret = str_pad($match[1],4,'0',STR_PAD_LEFT)
1176  . str_pad($match[2],4,'0',STR_PAD_LEFT)
1177  . str_pad($match[3],4,'0',STR_PAD_LEFT)
1178  . str_pad($match[4],4,'0',STR_PAD_LEFT)
1179  . str_pad($match[5],4,'0',STR_PAD_LEFT)
1180  . str_pad($match[6],4,'0',STR_PAD_LEFT)
1181  . str_pad($match[7],4,'0',STR_PAD_LEFT)
1182  . str_pad($match[8],4,'0',STR_PAD_LEFT);
1183  } elseif (preg_match("/^\:\:([0-9a-h\:]+)$/i",$string,$match)) {
1184  // short ipv6 with all starting symbols nulled
1185  $aAddr=explode(':',$match[1]);
1186  $ret='';
1187  foreach ($aAddr as $addr) {
1188  $ret.=str_pad($addr,4,'0',STR_PAD_LEFT);
1189  }
1190  $ret=str_pad($ret,32,'0',STR_PAD_LEFT);
1191  } elseif (preg_match("/^([0-9a-h\:]+)::([0-9a-h\:]+)$/i",$string,$match)) {
1192  // short ipv6 with middle part nulled
1193  $aStart=explode(':',$match[1]);
1194  $sStart='';
1195  foreach($aStart as $addr) {
1196  $sStart.=str_pad($addr,4,'0',STR_PAD_LEFT);
1197  }
1198  $aEnd = explode(':',$match[2]);
1199  $sEnd='';
1200  foreach($aEnd as $addr) {
1201  $sEnd.=str_pad($addr,4,'0',STR_PAD_LEFT);
1202  }
1203  $ret = $sStart
1204  . str_pad('',(32 - strlen($sStart . $sEnd)),'0',STR_PAD_LEFT)
1205  . $sEnd;
1206  } else {
1207  // unknown addressing
1208  $ret = $string;
1209  }
1210  return $ret;
1211  }
1212 }
1213 
elseif
if(! sqgetGlobalVar('sound', $sound, SQ_GET)) elseif($sound=='(none)')
Definition: testsound.php:25
$encode_header_key
$encode_header_key
Definition: config_default.php:170
$ret
$ret
Definition: webmail.php:172
$imapConnection
$imapConnection
Definition: message_details_bottom.php:74
$cnt
$cnt
Definition: options_identities.php:86
$date
$date
Definition: printer_friendly_bottom.php:61
Deliver\prepareMIME_Header
prepareMIME_Header($message, $boundary)
Definition: Deliver.class.php:468
$imapServerAddress
$imapServerAddress
Definition: config_default.php:202
sqimap_login
sqimap_login($username, $password, $imap_server_address, $imap_port, $hide)
Definition: imap_general.php:481
$edit_identity
$edit_identity
Definition: config_default.php:588
$rfc822_header
$rfc822_header
Definition: compose.php:362
$charset
$charset
Definition: view_text.php:67
Deliver\calculate_references
calculate_references($hdr)
Definition: Deliver.class.php:1130
$imap_stream
$imap_stream
Definition: bug_report.php:119
$mailbox
$mailbox
Definition: options.php:28
sprintf
powered by Systran sprintf(_("Number of supported language pairs: %s"), '36').' '
Definition: options.php:107
Deliver\mimeBoundary
mimeBoundary()
Definition: Deliver.class.php:1067
$username
global $username
Definition: validate.php:55
sqimap_mailbox_select
sqimap_mailbox_select($imap_stream, $mailbox)
Definition: imap_mailbox.php:238
$hide_auth_header
$hide_auth_header
Definition: config_default.php:605
$message
$message
Definition: download.php:54
Deliver
Definition: Deliver.class.php:29
Deliver\mail
mail(&$message, $stream=false, $reply_id=0, $reply_ent_id=0, $imap_stream=NULL, $extra=NULL)
Definition: Deliver.class.php:75
Deliver\foldLine
foldLine($header, $soft_wrap=78, $indent='', $hard_wrap=998)
Definition: Deliver.class.php:826
getHashedDir
getHashedDir($username, $dir, $hash_dirs='')
Definition: prefs.php:109
$invert_time
$invert_time
Definition: config_default.php:129
$attachment_dir
$attachment_dir
Definition: config_default.php:517
sqimap_logout
sqimap_logout($imap_stream)
Definition: imap_general.php:639
file_has_long_lines
file_has_long_lines($filename, $max_length)
Definition: global.php:614
Deliver\clean_crlf
clean_crlf(&$s)
Definition: Deliver.class.php:383
encodeHeader
encodeHeader($string)
Definition: mime.php:759
Deliver\preWriteToStream
preWriteToStream(&$s)
Definition: Deliver.class.php:416
SQ_SERVER
const SQ_SERVER
Definition: global.php:20
Deliver\send_mail
send_mail($message, $header, $boundary, $stream=false, &$raw_length, $extra=NULL)
Definition: Deliver.class.php:167
$filename
if(isset($override_type0)) if(isset($override_type1)) $filename
Definition: download.php:97
$data
$data
Definition: mailto.php:83
Deliver\writeToStream
writeToStream($stream, $data)
Definition: Deliver.class.php:427
Deliver\ip2hex
ip2hex($string)
Definition: Deliver.class.php:1166
Deliver\initStream
initStream($message, $length=0, $host='', $port='', $user='', $pass='')
Definition: Deliver.class.php:445
$type0
$type0
Definition: view_text.php:65
$version
global $version
Definition: config_default.php:26
sqimap_get_message
sqimap_get_message($imap_stream, $id, $mailbox)
Definition: imap_messages.php:1050
Deliver\timezone
timezone()
Definition: Deliver.class.php:1083
$imapPort
$imapPort
Definition: config_default.php:210
Deliver\writeBody
writeBody($message, $stream, &$length_raw, $boundary='')
Definition: Deliver.class.php:196
Deliver\writeBodyPart
writeBodyPart($message, $stream, &$length)
Definition: Deliver.class.php:258
Deliver\strip_crlf
strip_crlf(&$s)
Definition: Deliver.class.php:400
$stream
$stream
Definition: configtest.php:429
NULL
if(!defined('PAGE_NAME')) define('PAGE_NAME' NULL
Definition: validate.php:16
GenerateRandomString
GenerateRandomString($size, $chars, $flags=0)
Definition: strings.php:614
$encoding
$encoding
Definition: download.php:81
$header
$header
Definition: message_details_bottom.php:81
Deliver\getBCC
getBCC()
Definition: Deliver.class.php:456
Deliver\prepareRFC822_Header
prepareRFC822_Header(&$rfc822_header, $reply_rfc822_header, &$raw_length)
Definition: Deliver.class.php:565
$domain
$domain
Definition: config_default.php:118