[ Index ]
 

Code source de IMP H3 (4.1.5)

Accédez au Source d'autres logiciels libres

Classes | Fonctions | Variables | Constantes | Tables

title

Body

[fermer]

/lib/ -> Compose.php (source)

   1  <?php
   2  
   3  require_once 'Horde/MIME.php';
   4  
   5  /**
   6   * The virtual path to use for VFS data.
   7   */
   8  define('IMP_VFS_ATTACH_PATH', '.horde/imp/compose');
   9  
  10  /**
  11   * The virtual path to save linked attachments.
  12   */
  13  define('IMP_VFS_LINK_ATTACH_PATH', '.horde/imp/attachments');
  14  
  15  /**
  16   * The IMP_Compose:: class contains functions related to generating
  17   * outgoing mail messages.
  18   *
  19   * $Horde: imp/lib/Compose.php,v 1.107.2.41 2007/01/02 13:54:55 jan Exp $
  20   *
  21   * Copyright 2002-2007 Michael Slusarz <slusarz@bigworm.colorado.edu>
  22   *
  23   * See the enclosed file COPYING for license information (GPL). If you
  24   * did not receive this file, see http://www.fsf.org/copyleft/gpl.html.
  25   *
  26   * @author  Michael Slusarz <slusarz@bigworm.colorado.edu>
  27   * @since   IMP 4.0
  28   * @package IMP
  29   */
  30  class IMP_Compose {
  31  
  32      /**
  33       * The cached attachment data.
  34       *
  35       * @var array
  36       */
  37      var $_cache = array();
  38  
  39      /**
  40       * For findBody, the MIME ID of the "body" part.
  41       *
  42       * @var string
  43       */
  44      var $_mimeid = null;
  45  
  46      /**
  47       * The aggregate size of all attachments (in bytes).
  48       *
  49       * @var integer
  50       */
  51      var $_size = 0;
  52  
  53      /**
  54       * Constructor
  55       *
  56       * @param array $params  Parameters needed.
  57       */
  58      function IMP_Compose($params = array())
  59      {
  60          if (isset($params['cacheID'])) {
  61              $this->_retrieveMimeCache($params['cacheID']);
  62          }
  63      }
  64  
  65      /**
  66       * Sends a message.
  67       *
  68       * @param string $email          The e-mail list to send to.
  69       * @param IMP_Headers &$headers  The IMP_Headers object holding this
  70       *                               messages headers.
  71       * @param mixed &$message        Either the message text (string) or a
  72       *                               MIME_Message object that contains the
  73       *                               text to send.
  74       * @param string $charset        The charset that was used for the headers.
  75       *
  76       * @return mixed  True on success, PEAR_Error on error.
  77       */
  78      function sendMessage($email, &$headers, &$message, $charset)
  79      {
  80          global $conf;
  81  
  82          require_once 'Mail.php';
  83  
  84          /* We don't actually want to alter the contents of the $conf['mailer']
  85           * array, so we make a copy of the current settings. We will apply our
  86           * modifications (if any) to the copy, instead. */
  87          $params = $conf['mailer']['params'];
  88          $driver = $conf['mailer']['type'];
  89  
  90          /* If user specifies an SMTP server on login, force SMTP mailer. */
  91          if (!empty($conf['server']['change_smtphost'])) {
  92              $driver = 'smtp';
  93              if (empty($params['mailer']['auth'])) {
  94                  $params['mailer']['auth'] = '1';
  95              }
  96          }
  97  
  98          /* Force the SMTP host and port value to the current SMTP server if
  99           * one has been selected for this connection. */
 100          if (!empty($_SESSION['imp']['smtphost'])) {
 101              $params['host'] = $_SESSION['imp']['smtphost'];
 102          }
 103          if (!empty($_SESSION['imp']['smtpport'])) {
 104              $params['port'] = $_SESSION['imp']['smtpport'];
 105          }
 106  
 107          /* If SMTP authentication has been requested, use either the username
 108           * and password provided in the configuration or populate the username
 109           * and password fields based on the current values for the user. Note
 110           * that we assume that the username and password values from the
 111           * current IMAP / POP3 connection are valid for SMTP authentication as
 112           * well. */
 113          if (!empty($params['auth']) && empty($params['username'])) {
 114              $params['username'] = $_SESSION['imp']['user'];
 115              $params['password'] = Secret::read(Secret::getKey('imp'), $_SESSION['imp']['pass']);
 116          }
 117  
 118          /* Add the site headers. */
 119          $headers->addSiteHeaders();
 120  
 121          /* If $message is a string, we need to get a MIME_Message object to
 122           * encode the headers. */
 123          if (is_string($message)) {
 124              $msg = $message;
 125              $mime_message = &new MIME_Message($_SESSION['imp']['maildomain']);
 126              $headerArray = $mime_message->encode($headers->toArray(), $charset);
 127          } else {
 128              $msg = $message->toString();
 129              $headerArray = $message->encode($headers->toArray(), $charset);
 130          }
 131  
 132          /* Make sure the message has a trailing newline. */
 133          if (substr($msg, -1) != "\n") {
 134              $msg .= "\n";
 135          }
 136  
 137          $mailer = Mail::factory($driver, $params);
 138          if (is_a($mailer, 'PEAR_Error')) {
 139              return $mailer;
 140          }
 141  
 142          /* Properly encode the addresses we're sending to. */
 143          $email = MIME::encodeAddress($email, null, $_SESSION['imp']['maildomain']);
 144          if (is_a($email, 'PEAR_Error')) {
 145              return $email;
 146          }
 147  
 148          /* Validate the recipient addresses. */
 149          require_once 'Mail/RFC822.php';
 150          $parser = &new Mail_RFC822();
 151          $result = $parser->parseAddressList($email, $_SESSION['imp']['maildomain'], null, true);
 152          if (is_a($result, 'PEAR_Error')) {
 153              return $result;
 154          }
 155  
 156          $result = $mailer->send($email, $headerArray, $msg);
 157  
 158          if (is_a($result, 'PEAR_Error') &&
 159              $conf['mailer']['type'] == 'sendmail') {
 160              // Interpret return values as defined in /usr/include/sysexits.h
 161              switch ($result->getCode()) {
 162              case 64: // EX_USAGE
 163                  $error = 'sendmail: ' . _("command line usage error") . ' (64)';
 164                  break;
 165  
 166              case 65: // EX_DATAERR
 167                  $error = 'sendmail: ' . _("data format error") . ' (65)';
 168                  break;
 169  
 170              case 66: // EX_NOINPUT
 171                  $error = 'sendmail: ' . _("cannot open input") . ' (66)';
 172                  break;
 173  
 174              case 67: // EX_NOUSER
 175                  $error = 'sendmail: ' . _("addressee unknown") . ' (67)';
 176                  break;
 177  
 178              case 68: // EX_NOHOST
 179                  $error = 'sendmail: ' . _("host name unknown") . ' (68)';
 180                  break;
 181  
 182              case 69: // EX_UNAVAILABLE
 183                  $error = 'sendmail: ' . _("service unavailable") . ' (69)';
 184                  break;
 185  
 186              case 70: // EX_SOFTWARE
 187                  $error = 'sendmail: ' . _("internal software error") . ' (70)';
 188                  break;
 189  
 190              case 71: // EX_OSERR
 191                  $error = 'sendmail: ' . _("system error") . ' (71)';
 192                  break;
 193  
 194              case 72: // EX_OSFILE
 195                  $error = 'sendmail: ' . _("critical system file missing") . ' (72)';
 196                  break;
 197  
 198              case 73: // EX_CANTCREAT
 199                  $error = 'sendmail: ' . _("cannot create output file") . ' (73)';
 200                  break;
 201  
 202              case 74: // EX_IOERR
 203                  $error = 'sendmail: ' . _("input/output error") . ' (74)';
 204                  break;
 205  
 206              case 75: // EX_TEMPFAIL
 207                  $error = 'sendmail: ' . _("temporary failure") . ' (75)';
 208                  break;
 209  
 210              case 76: // EX_PROTOCOL
 211                  $error = 'sendmail: ' . _("remote error in protocol") . ' (76)';
 212                  break;
 213  
 214              case 77: // EX_NOPERM
 215                  $error = 'sendmail: ' . _("permission denied") . ' (77)';
 216                  break;
 217  
 218              case 78: // EX_CONFIG
 219                  $error = 'sendmail: ' . _("configuration error") . ' (78)';
 220                  break;
 221  
 222              case 79: // EX_NOTFOUND
 223                  $error = 'sendmail: ' . _("entry not found") . ' (79)';
 224                  break;
 225  
 226              default:
 227                  $error = $result;
 228              }
 229              return PEAR::raiseError($error);
 230          }
 231  
 232          return $result;
 233      }
 234  
 235      /**
 236       * Finds the main "body" text part (if any) in a message.
 237       *
 238       * @param IMP_Contents &$imp_contents  An IMP_Contents object.
 239       *
 240       * @return string  The text of the "body" part of the message.
 241       *                 Returns an empty string if no "body" found.
 242       */
 243      function findBody(&$imp_contents)
 244      {
 245          if (is_null($this->_mimeid)) {
 246              $this->_mimeid = $imp_contents->findBody();
 247              if (is_null($this->_mimeid)) {
 248                  return '';
 249              }
 250          }
 251  
 252          $mime_part = &$imp_contents->getDecodedMIMEPart($this->_mimeid);
 253          $body = $mime_part->getContents();
 254  
 255          //if ($mime_message->getType() == 'multipart/encrypted') {
 256              /* TODO: Maybe someday I can figure out how to show embedded
 257               * text parts here.  But for now, just output this message. */
 258          //    return '[' . _("Original message was encrypted") . ']';
 259          //}
 260  
 261          if ($mime_part->getSubType() == 'html') {
 262              require_once 'Horde/Text/Filter.php';
 263              return Text_Filter::filter($body, 'html2text', array('wrap' => ($mime_part->getContentTypeParameter('format') != 'flowed'), 'charset' => $mime_part->getCharset()));
 264          } else {
 265              return $body;
 266          }
 267      }
 268  
 269      /**
 270       * Returns the ID of the MIME part containing the "body".
 271       *
 272       * @param IMP_Contents &$imp_contents  An IMP_Contents object.
 273       *
 274       * @return string  The ID of the mime part's body.
 275       */
 276      function getBodyId(&$imp_contents)
 277      {
 278          if (is_null($this->_mimeid)) {
 279              $this->findBody($imp_contents);
 280          }
 281          return $this->_mimeid;
 282      }
 283  
 284      /**
 285       * Determine the reply text for a message.
 286       *
 287       * @param IMP_Contents $imp_contents  An IMP_Contents object.
 288       * @param string $from                The email address of the
 289       *                                    original sender.
 290       * @param IMP_Headers $h              The IMP_Headers object for
 291       *                                    the message.
 292       *
 293       * @return string  The text of the body part of the message to use
 294       *                 for the reply.
 295       */
 296      function replyMessage(&$imp_contents, $from, &$h)
 297      {
 298          global $prefs;
 299  
 300          if (!$prefs->getValue('reply_quote')) {
 301              return '';
 302          }
 303  
 304          $mime_message = $imp_contents->getMIMEMessage();
 305          $msg = $this->findBody($imp_contents);
 306          $msg = $mime_message->replaceEOL($msg, "\n");
 307  
 308          if (!is_null($this->_mimeid)) {
 309              require_once 'Text/Flowed.php';
 310              $old_part = $mime_message->getPart($this->_mimeid);
 311              if ($old_part->getContentTypeParameter('format') == 'flowed') {
 312                  /* We need to convert the flowed text to fixed text before
 313                   * we begin working on it. */
 314                  $flowed = &new Text_Flowed($msg);
 315                  if ((String::lower($mime_message->getContentTypeParameter('delsp')) == 'yes') &&
 316                      method_exists($flowed, 'setDelSp')) {
 317                      $flowed->setDelSp(true);
 318                  }
 319                  $msg = $flowed->toFixed(false);
 320              } else {
 321                  /* If the input is *not* in flowed format, make sure there is
 322                   * no padding at the end of lines. */
 323                  $msg = preg_replace("/\s*\n/U", "\n", $msg);
 324              }
 325  
 326              $msg = String::convertCharset($msg, $old_part->getCharset());
 327  
 328              $flowed = &new Text_Flowed($msg);
 329              if (method_exists($flowed, 'setDelSp')) {
 330                  $flowed->setDelSp(true);
 331              }
 332              $msg = $flowed->toFlowed(true);
 333          }
 334  
 335          if (empty($msg)) {
 336              $msg = '[' . _("No message body text") . ']';
 337          } elseif ($prefs->getValue('reply_headers') && !empty($h)) {
 338              $msghead = '----- ';
 339              if (($from = $h->getFromAddress())) {
 340                  $msghead .= sprintf(_("Message from %s"), $from);
 341              } else {
 342                  $msghead .= _("Message");
 343              }
 344  
 345              /* Extra '-'s line up with "End Message" below. */
 346              $msghead .= " ---------\n";
 347              $msghead .= $this->_getMsgHeaders($h);
 348              $msg = $msghead . "\n\n" . $msg;
 349              if (!empty($from)) {
 350                  $msg .= "\n\n" . '----- ' . sprintf(_("End message from %s"), $from) . " -----\n";
 351              } else {
 352                  $msg .= "\n\n" . '----- ' . _("End message") . " -----\n";
 353              }
 354          } else {
 355              $msg = $this->_expandAttribution($prefs->getValue('attrib_text'), $from, $h) . "\n\n" . $msg;
 356          }
 357  
 358          return $msg . "\n";
 359      }
 360  
 361      /**
 362       * Determine the text for a forwarded message.
 363       *
 364       * @param IMP_Contents &$imp_contents  An IMP_Contents object.
 365       * @param IMP_Headers &$h              The IMP_Headers object for
 366       *                                     the message.
 367       *
 368       * @return string  The text of the body part of the message to use
 369       *                 for the forward.
 370       */
 371      function forwardMessage(&$imp_contents, &$h)
 372      {
 373          require_once 'Horde/Text.php';
 374  
 375          $msg = "\n\n\n----- ";
 376  
 377          if (($from = $h->getFromAddress())) {
 378              $msg .= sprintf(_("Forwarded message from %s"), $from);
 379          } else {
 380              $msg .= _("Forwarded message");
 381          }
 382  
 383          $msg .= " -----\n";
 384          $msg .= $this->_getMsgHeaders($h);
 385          $msg .= "\n";
 386  
 387          $fwd_msg = $this->findBody($imp_contents);
 388          if (!is_null($this->_mimeid)) {
 389              $mime_message = $imp_contents->getMIMEMessage();
 390              $old_part = $mime_message->getPart($this->_mimeid);
 391              $fwd_msg = String::convertCharset($fwd_msg, $old_part->getCharset());
 392          }
 393  
 394          $msg .= $fwd_msg;
 395          $msg .= "\n\n----- " . _("End forwarded message") . " -----\n";
 396  
 397          return $msg;
 398      }
 399  
 400      /**
 401       * Determine the header information to display in the forward/reply.
 402       *
 403       * @access private
 404       *
 405       * @param IMP_Headers &$h  The IMP_Headers object for the message.
 406       *
 407       * @return string  The header information for the original message.
 408       */
 409      function _getMsgHeaders(&$h)
 410      {
 411          $text = '';
 412  
 413          if (($date_ob = $h->getOb('date', true))) {
 414              $text .= _("    Date: ") . $date_ob . "\n";
 415          }
 416          if (($from_ob = MIME::addrArray2String($h->getOb('from')))) {
 417              $text .= _("    From: ") . $from_ob . "\n";
 418          }
 419          if (($rep_ob = MIME::addrArray2String($h->getOb('reply_to')))) {
 420              $text .= _("Reply-To: ") . $rep_ob . "\n";
 421          }
 422          if (($sub_ob = $h->getOb('subject', true))) {
 423              $text .= _(" Subject: ") . $sub_ob . "\n";
 424          }
 425          if (($to_ob = MIME::addrArray2String($h->getOb('to')))) {
 426              $text .= _("      To: ") . $to_ob . "\n";
 427          }
 428          if (($cc_ob = MIME::addrArray2String($h->getOb('cc')))) {
 429              $text .= _("      Cc: ") . $cc_ob . "\n";
 430          }
 431  
 432          return $text;
 433      }
 434  
 435      /**
 436       * Adds an attachment to a MIME_Part from an uploaded file.
 437       * The actual attachment data is stored in a separate file - the
 438       * MIME_Part information entries 'temp_filename' and 'temp_filetype'
 439       * are set with this information.
 440       *
 441       * @param string $name         The input field name from the form.
 442       * @param string $disposition  The disposition to use for the file.
 443       *
 444       * @return mixed  Returns the filename on success.
 445       *                Returns PEAR_Error on error.
 446       */
 447      function addUploadAttachment($name, $disposition)
 448      {
 449          global $conf;
 450  
 451          $res = Browser::wasFileUploaded($name, _("attachment"));
 452          if (is_a($res, 'PEAR_Error')) {
 453              return $res;
 454          }
 455  
 456          $filename = $_FILES[$name]['name'];
 457          $tempfile = $_FILES[$name]['tmp_name'];
 458  
 459          /* Check for filesize limitations. */
 460          if (!empty($conf['compose']['attach_size_limit']) &&
 461              (($conf['compose']['attach_size_limit'] - $this->sizeOfAttachments() - $_FILES[$name]['size']) < 0)) {
 462              return PEAR::raiseError(sprintf(_("Attached file \"%s\" exceeds the attachment size limits. File NOT attached."), $filename), 'horde.error');
 463          }
 464  
 465          /* Store the data in a MIME_Part. Some browsers do not send the MIME
 466             type so try an educated guess. */
 467          if (!empty($_FILES[$name]['type']) &&
 468              ($_FILES[$name]['type'] != 'application/octet-stream')) {
 469              $part = &new MIME_Part($_FILES[$name]['type']);
 470          } else {
 471              require_once 'Horde/MIME/Magic.php';
 472              /* Try to determine the MIME type from 1) analysis of the file
 473               * (if available) and, if that fails, 2) from the extension. We
 474               * do it in this order here because, most likely, if a browser
 475               * can't identify the type of a file, it is because the file
 476               * extensions isn't available and/or recognized. */
 477              if (!($type = MIME_Magic::analyzeFile($tempfile, !empty($conf['mime']['magic_db']) ? $conf['mime']['magic_db'] : null))) {
 478                  $type = MIME_Magic::filenameToMIME($filename, false);
 479              }
 480              $part = &new MIME_Part($type);
 481          }
 482          $part->setCharset(NLS::getCharset());
 483          $part->setName(MIME::encode($filename));
 484          $part->setBytes($_FILES[$name]['size']);
 485          if ($disposition) {
 486              $part->setDisposition($disposition);
 487          }
 488  
 489          if ($conf['compose']['use_vfs']) {
 490              $attachment = $tempfile;
 491          } else {
 492              $attachment = Horde::getTempFile('impatt', false);
 493              move_uploaded_file($tempfile, $attachment);
 494          }
 495  
 496          /* Store the data. */
 497          $result = $this->_storeAttachment($part, $attachment);
 498          if (is_a($result, 'PEAR_Error')) {
 499              return $result;
 500          }
 501  
 502          return $filename;
 503      }
 504  
 505      /**
 506       * Adds an attachment to a MIME_Part from data existing in the part.
 507       *
 508       * @param MIME_Part &$part  The MIME_Part object that contains the
 509       *                          attachment data.
 510       *
 511       * @return PEAR_Error  Returns a PEAR_Error object on error.
 512       */
 513      function addMIMEPartAttachment(&$part)
 514      {
 515          global $conf;
 516  
 517          $type = $part->getType();
 518          $vfs = $conf['compose']['use_vfs'];
 519  
 520          /* Decode the contents. */
 521          $part->transferDecodeContents();
 522  
 523          /* Try to determine the MIME type from 1) the extension and
 524           * then 2) analysis of the file (if available). */
 525          if ($type == 'application/octet-stream') {
 526              require_once 'Horde/MIME/Magic.php';
 527              $type = MIME_Magic::filenameToMIME($part->getName(true), false);
 528          }
 529  
 530          /* Extract the data from the currently existing MIME_Part and then
 531             delete it. If this is an unknown MIME part, we must save to a
 532             temporary file to run the file analysis on it. */
 533          if (!$vfs) {
 534              $attachment = Horde::getTempFile('impatt', $vfs);
 535              $fp = fopen($attachment, 'w');
 536              fwrite($fp, $part->getContents());
 537              fclose($fp);
 538  
 539              if (($type == 'application/octet-stream') &&
 540                  ($analyzetype = MIME_Magic::analyzeFile($attachment, !empty($conf['mime']['magic_db']) ? $conf['mime']['magic_db'] : null))) {
 541                  $type = $analyzetype;
 542              }
 543          } elseif (($type == 'application/octet-stream') &&
 544                    ($analyzetype = MIME_Magic::analyzeData($part->getContents(), !empty($conf['mime']['magic_db']) ? $conf['mime']['magic_db'] : null))) {
 545              $type = $analyzetype;
 546          }
 547  
 548          $part->setType($type);
 549  
 550          /* Set the size of the Part explicitly since we delete the contents
 551             later on in this function. */
 552          $part->setBytes($part->getBytes());
 553  
 554          /* Check for filesize limitations. */
 555          if (!empty($conf['compose']['attach_size_limit']) &&
 556              (($conf['compose']['attach_size_limit'] - $this->sizeOfAttachments() - $part->getBytes()) < 0)) {
 557              return PEAR::raiseError(sprintf(_("Attached file \"%s\" exceeds the attachment size limits. File NOT attached."), $part->getName()), 'horde.error');
 558          }
 559  
 560          /* Store the data. */
 561          if ($vfs) {
 562              $vfs_data = $part->getContents();
 563              $part->clearContents();
 564              $this->_storeAttachment($part, $vfs_data, false);
 565          } else {
 566              $part->clearContents();
 567              $this->_storeAttachment($part, $attachment);
 568          }
 569      }
 570  
 571      /**
 572       * Stores the attachment data in its correct location.
 573       *
 574       * @access private
 575       *
 576       * @param MIME_Part &$part   The MIME_Part of the attachment.
 577       * @param string $data       Either the filename of the attachment or, if
 578       *                           $vfs_file is false, the attachment data.
 579       * @param boolean $vfs_file  If using VFS, is $data a filename?
 580       */
 581      function _storeAttachment(&$part, $data, $vfs_file = true)
 582      {
 583          global $conf;
 584  
 585          /* Store in VFS. */
 586          if ($conf['compose']['use_vfs']) {
 587              require_once 'VFS.php';
 588              require_once 'VFS/GC.php';
 589              $vfs = &VFS::singleton($conf['vfs']['type'], Horde::getDriverConfig('vfs', $conf['vfs']['type']));
 590              VFS_GC::gc($vfs, IMP_VFS_ATTACH_PATH, 86400);
 591              $cacheID = md5(mt_rand() . microtime());
 592              if ($vfs_file) {
 593                  $result = $vfs->write(IMP_VFS_ATTACH_PATH, $cacheID, $data, true);
 594              } else {
 595                  $result = $vfs->writeData(IMP_VFS_ATTACH_PATH, $cacheID, $data, true);
 596              }
 597              if (is_a($result, 'PEAR_Error')) {
 598                  return $result;
 599              }
 600              $part->setInformation('temp_filename', $cacheID);
 601              $part->setInformation('temp_filetype', 'vfs');
 602          } else {
 603              chmod($data, 0600);
 604              $part->setInformation('temp_filename', $data);
 605              $part->setInformation('temp_filetype', 'file');
 606          }
 607  
 608          /* Add the size information to the counter. */
 609          $this->_size += $part->getBytes();
 610  
 611          $this->_cache[] = $part;
 612      }
 613  
 614      /**
 615       * Delete attached files.
 616       *
 617       * @param mixed $number  Either a single integer or an array of integers
 618       *                       corresponding to the attachment position.
 619       *
 620       * @return array  The list of deleted filenames (MIME encoded).
 621       */
 622      function deleteAttachment($number)
 623      {
 624          global $conf;
 625  
 626          $names = array();
 627  
 628          if (!is_array($number)) {
 629              $number = array($number);
 630          }
 631  
 632          foreach ($number as $val) {
 633              $val--;
 634              $part = &$this->_cache[$val];
 635              $filename = $part->getInformation('temp_filename');
 636              if ($part->getInformation('temp_filetype') == 'vfs') {
 637                  /* Delete from VFS. */
 638                  require_once 'VFS.php';
 639                  $vfs = &VFS::singleton($conf['vfs']['type'], Horde::getDriverConfig('vfs', $conf['vfs']['type']));
 640                  $vfs->deleteFile(IMP_VFS_ATTACH_PATH, $filename);
 641              } else {
 642                  /* Delete from filesystem. */
 643                  @unlink($filename);
 644              }
 645  
 646              $part->setInformation('temp_filename', '');
 647              $part->setInformation('temp_filetype', '');
 648  
 649              $names[] = $part->getName(false, true);
 650  
 651              /* Remove the size information from the counter. */
 652              $this->_size -= $part->getBytes();
 653  
 654              unset($this->_cache[$val]);
 655          }
 656  
 657          /* Reorder the attachments. */
 658          $this->_cache = array_values($this->_cache);
 659  
 660          return $names;
 661      }
 662  
 663      /**
 664       * Deletes all attachments.
 665       */
 666      function deleteAllAttachments()
 667      {
 668          $numbers = array();
 669  
 670          for ($i = 1; $i <= $this->numberOfAttachments(); $i++) {
 671              $numbers[] = $i;
 672          }
 673  
 674          $this->deleteAttachment($numbers);
 675      }
 676  
 677      /**
 678       * Updates information in a specific attachment.
 679       *
 680       * @param integer $number  The attachment to update.
 681       * @param array $params    An array of update information.
 682       * <pre>
 683       * 'disposition'  --  The Content-Disposition value.
 684       * 'description'  --  The Content-Description value.
 685       * </pre>
 686       */
 687      function updateAttachment($number, $params)
 688      {
 689          $number--;
 690          $this->_cache[$number]->setDisposition($params['disposition']);
 691          $this->_cache[$number]->setDescription($params['description']);
 692      }
 693  
 694      /**
 695       * Returns the list of current attachments.
 696       *
 697       * @return array  The list of attachments.
 698       */
 699      function getAttachments()
 700      {
 701          return $this->_cache;
 702      }
 703  
 704      /**
 705       * Returns the number of attachments currently in this message.
 706       *
 707       * @return integer  The number of attachments in this message.
 708       */
 709      function numberOfAttachments()
 710      {
 711          return count($this->_cache);
 712      }
 713  
 714      /**
 715       * Returns the size of the attachments in bytes.
 716       *
 717       * @return integer  The size of the attachments (in bytes).
 718       */
 719      function sizeOfAttachments()
 720      {
 721          return $this->_size;
 722      }
 723  
 724      /**
 725       * Build a single attachment part with its data.
 726       *
 727       * @param integer $id  The ID of the part to rebuild.
 728       *
 729       * @return MIME_Part  The MIME_Part with its contents.
 730       */
 731      function buildAttachment($id)
 732      {
 733          $part = $this->_cache[($id - 1)];
 734          $this->_buildPartData($part);
 735          return $part;
 736      }
 737  
 738      /**
 739       * Build the MIME_Part attachments from the temporary file data.
 740       *
 741       * @param MIME_Part &$base  The base MIME_Part object to add the
 742       *                          attachments to.
 743       * @param string $charset   The charset to use for the filename.
 744       */
 745      function buildAllAttachments(&$base, $charset)
 746      {
 747          foreach ($this->_cache as $part) {
 748              /* Store the data inside the current part. */
 749              $this->_buildPartData($part);
 750  
 751              /* Convert the charset of the filename. */
 752              $name = String::convertCharset($part->getName(true), NLS::getCharset(), $charset);
 753              $part->setName(MIME::encode($name, $charset));
 754  
 755              /* Add to the base part. */
 756              $base->addPart($part);
 757          }
 758      }
 759  
 760      /**
 761       * Takes the temporary data for a single part and puts it into the
 762       * contents of that part.
 763       *
 764       * @access private
 765       *
 766       * @param MIME_Part &$part  The part to rebuild data into.
 767       */
 768      function _buildPartData(&$part)
 769      {
 770          global $conf;
 771  
 772          $filename = $part->getInformation('temp_filename');
 773          if ($part->getInformation('temp_filetype') == 'vfs') {
 774              require_once 'VFS.php';
 775              $vfs = &VFS::singleton($conf['vfs']['type'], Horde::getDriverConfig('vfs', $conf['vfs']['type']));
 776              $data = $vfs->read(IMP_VFS_ATTACH_PATH, $filename);
 777          } else {
 778              $data = file_get_contents($filename);
 779          }
 780  
 781          /* Set the part's contents to the raw attachment data. */
 782          $part->setContents($data);
 783      }
 784  
 785      /**
 786       * Expand macros in attribution text when replying to messages.
 787       *
 788       * @access private
 789       *
 790       * @param string $line     The line of attribution text.
 791       * @param string $from     The email address of the original
 792       *                         sender.
 793       * @param IMP_Headers &$h  The IMP_Headers object for the message.
 794       *
 795       * @return string  The attribution text.
 796       */
 797      function _expandAttribution($line, $from, &$h)
 798      {
 799          $addressList = '';
 800          $nameList = '';
 801  
 802          /* First we'll get a comma seperated list of email addresses
 803             and a comma seperated list of personal names out of $from
 804             (there just might be more than one of each). */
 805          foreach (IMP::parseAddressList($from) as $entry) {
 806              if (isset($entry->mailbox) && isset($entry->host)) {
 807                  if (strlen($addressList) > 0) {
 808                      $addressList .= ', ';
 809                  }
 810                  $addressList .= $entry->mailbox . '@' . $entry->host;
 811              } elseif (isset($entry->mailbox)) {
 812                  if (strlen($addressList) > 0) {
 813                      $addressList .= ', ';
 814                  }
 815                  $addressList .= $entry->mailbox;
 816              }
 817              if (isset($entry->personal)) {
 818                  if (strlen($nameList) > 0) {
 819                      $nameList .= ', ';
 820                  }
 821                  $nameList .= $entry->personal;
 822              } elseif (isset($entry->mailbox)) {
 823                  if (strlen($nameList) > 0) {
 824                      $nameList .= ', ';
 825                  }
 826                  $nameList .= $entry->mailbox;
 827              }
 828          }
 829  
 830          /* Define the macros. */
 831          if (is_array($message_id = $h->getOb('message_id'))) {
 832              $message_id = reset($message_id);
 833          }
 834          if (!($subject = $h->getOb('subject', true))) {
 835              $subject = _("[No Subject]");
 836          }
 837          $udate = strtotime($h->getOb('date', true));
 838  
 839          $match = array(
 840              /* New line. */
 841              '/%n/' => "\n",
 842  
 843              /* The '%' character. */
 844              '/%%/' => '%',
 845  
 846              /* Name and email address of original sender. */
 847              '/%f/' => $from,
 848  
 849              /* Senders email address(es). */
 850              '/%a/' => $addressList,
 851  
 852              /* Senders name(s). */
 853              '/%p/' => $nameList,
 854  
 855              /* RFC 822 date and time. */
 856              '/%r/' => $h->getOb('date', true),
 857  
 858              /* Date as ddd, dd mmm yyyy. */
 859              '/%d/' => String::convertCharset(@strftime("%a, %d %b %Y", $udate), NLS::getExternalCharset()),
 860  
 861              /* Date in locale's default. */
 862              '/%x/' => String::convertCharset(@strftime("%x", $udate), NLS::getExternalCharset()),
 863  
 864              /* Date and time in locale's default. */
 865              '/%c/' => String::convertCharset(@strftime("%c", $udate), NLS::getExternalCharset()),
 866  
 867              /* Message-ID. */
 868              '/%m/' => $message_id,
 869  
 870              /* Message subject. */
 871              '/%s/' => $subject
 872          );
 873  
 874          return (preg_replace(array_keys($match), array_values($match), $line));
 875      }
 876  
 877      /**
 878       * Obtains the cached array of MIME_Parts to be attached to this message.
 879       *
 880       * @access private
 881       *
 882       * @param string $cacheID  The cacheID of the session object.
 883       */
 884      function _retrieveMimeCache($cacheID)
 885      {
 886          if ($cacheID) {
 887              require_once 'Horde/SessionObjects.php';
 888              $cacheSess = &Horde_SessionObjects::singleton();
 889              $result = $cacheSess->query($cacheID);
 890              $cacheSess->setPruneFlag($cacheID, true);
 891              $this->_cache = &$result['cache'];
 892              $this->_size = &$result['size'];
 893          }
 894      }
 895  
 896      /**
 897       * Obtains the cache ID for the session object that contains the
 898       * MIME_Part objects to be attached to this message.
 899       * This function needs to be run at least once per pageload to save the
 900       * session object.
 901       *
 902       * @return string  The message cache ID if the object needs to be saved.
 903       *                 Else, false is returned.
 904       */
 905      function getMessageCacheId()
 906      {
 907          if (!empty($this->_cache)) {
 908              require_once 'Horde/SessionObjects.php';
 909              $cacheSess = &Horde_SessionObjects::singleton();
 910              $store = array(
 911                  'cache' => $this->_cache,
 912                  'size' => $this->_size
 913              );
 914              return $cacheSess->storeOid($store);
 915          } else {
 916              return false;
 917          }
 918      }
 919  
 920      /**
 921       * How many more attachments are allowed?
 922       *
 923       * @return mixed  Returns true if no attachment limit.
 924       *                Else returns the number of additional attachments
 925       *                allowed.
 926       */
 927      function additionalAttachmentsAllowed()
 928      {
 929          global $conf;
 930  
 931          if (!empty($conf['compose']['attach_count_limit'])) {
 932              return $conf['compose']['attach_count_limit'] - $this->numberOfAttachments();
 933          } else {
 934              return true;
 935          }
 936      }
 937  
 938      /**
 939       * What is the maximum attachment size allowed?
 940       *
 941       * @return integer  The maximum attachment size allowed (in bytes).
 942       */
 943      function maxAttachmentSize()
 944      {
 945          global $conf, $imp;
 946  
 947          $size = $imp['file_upload'];
 948  
 949          if (!empty($conf['compose']['attach_size_limit'])) {
 950              $size = min($size, max($conf['compose']['attach_size_limit'] - $this->sizeOfAttachments(), 0));
 951          }
 952  
 953          return $size;
 954      }
 955  
 956      /**
 957       * Adds the attachments to the message (in the case of a forward with
 958       * attachments).
 959       * This function MUST be called after IMP_Compose::forwardMessage().
 960       *
 961       * @param IMP_Contents &$contents  An IMP_Contents object.
 962       *
 963       * @return array  An array of PEAR_Error object on error.
 964       *                An empty array if successful.
 965       */
 966      function attachFilesFromMessage(&$contents)
 967      {
 968          $errors = array();
 969  
 970          $dl_list = $contents->getDownloadAllList(true);
 971          $mime_message = $contents->getMIMEMessage();
 972  
 973          foreach ($dl_list as $val) {
 974              if (is_null($this->_mimeid) || ($val != $this->_mimeid)) {
 975                  $mime = $mime_message->getPart($val);
 976                  if (!empty($mime)) {
 977                      $res = $this->addMIMEPartAttachment($mime);
 978                      if (is_a($res, 'PEAR_Error')) {
 979                          $errors[] = $res;
 980                      }
 981                  }
 982              }
 983          }
 984  
 985          return $errors;
 986      }
 987  
 988      /**
 989       * Convert a text/html MIME_Part message with embedded image links to
 990       * a multipart/related MIME_Part with the image data embedded in the part.
 991       *
 992       * @param MIME_Part $mime_part  The text/html MIME_Part object.
 993       *
 994       * @return MIME_Part  The modified MIME_Part.
 995       */
 996      function convertToMultipartRelated($mime_part)
 997      {
 998          /* Return immediately if HTTP_Request is not available. */
 999          $inc = include_once 'HTTP/Request.php';
1000          if ($inc === false) {
1001              return $mime_part;
1002          }
1003  
1004          /* Return immediately if not an HTML part. */
1005          if ($mime_part->getType() != 'text/html') {
1006              return $mime_part;
1007          }
1008  
1009          /* Scan for 'img' tags - specifically the 'src' parameter. If
1010           * none, return the original MIME_Part. */
1011          if (!preg_match_all('/<img[^>]+src\s*\=\s*([^\s]+)\s+/iU', $mime_part->getContents(), $results)) {
1012              return $mime_part;
1013          }
1014  
1015          /* Go through list of results, download the image, and create
1016           * MIME_Part objects with the data. */
1017          $img_data = array();
1018          $img_parts = array();
1019          foreach ($results[1] as $url) {
1020              /* Strip any quotation marks and convert '&amp;' to '&' (since
1021               * HTTP_Request doesn't handle the former correctly). */
1022              $img_url = str_replace('&amp;', '&', trim($url, '"\''));
1023  
1024              /* Attempt to download the image data. */
1025              $request = &new HTTP_Request($img_url, array('timeout' => 5));
1026              $request->sendRequest();
1027  
1028              if ($request->getResponseCode() == '200') {
1029                  /* We need to determine the image type.  Try getting
1030                   * that information from the returned HTTP
1031                   * content-type header.  TODO: Use MIME_Magic if this
1032                   * fails (?) */
1033                  $part = &new MIME_Part($request->getResponseHeader('content-type'), $request->getResponseBody(), null, 'attachment', '8bit');
1034                  $img_data[$url] = '"cid:' . $part->setContentID() . '"';
1035                  $img_parts[] = $part;
1036              }
1037          }
1038  
1039          /* If we could not successfully download any data, return the
1040           * original MIME_Part now. */
1041          if (empty($img_data)) {
1042              return $mime_part;
1043          }
1044  
1045          /* Replace the URLs with with CID tags. */
1046          $text = $mime_part->getContents();
1047          $text = str_replace(array_keys($img_data), array_values($img_data), $text);
1048          $mime_part->setContents($text);
1049  
1050          /* Create new multipart/related part. */
1051          $related = &new MIME_Part('multipart/related');
1052  
1053          /* Get the CID for the 'root' part. Although by default the
1054           * first part is the root part (RFC 2387 [3.2]), we may as
1055           * well be explicit and put the CID in the 'start'
1056           * parameter. */
1057          $related->setContentTypeParameter('start', $mime_part->setContentID());
1058  
1059          /* Add the root part and the various images to the multipart
1060           * object. */
1061          $related->addPart($mime_part);
1062          foreach ($img_parts as $val) {
1063              $related->addPart($val);
1064          }
1065  
1066          return $related;
1067      }
1068  
1069      /**
1070       * Remove all attachments from an email message and replace with
1071       * urls to downloadable links. Should properly save all
1072       * attachments to a new folder and remove the MIME_Parts for the
1073       * attachments.
1074       *
1075       * @param string    $baseurl    The base URL for creating the links.
1076       * @param MIME_Part $base_part  The body of the message.
1077       * @param string    $auth       The authorized user who owns the attachments.
1078       *
1079       * @return MIME_Part  Modified part with links to attachments. Returns
1080       *                    PEAR_Error on error.
1081       */
1082      function linkAttachments($baseurl, $base_part, $auth)
1083      {
1084          global $conf, $prefs;
1085  
1086          if (!$conf['compose']['link_attachments']) {
1087              return PEAR::raiseError(_("Linked attachments are forbidden."));
1088          }
1089  
1090          require_once 'VFS.php';
1091          $vfs = &VFS::singleton($conf['vfs']['type'], Horde::getDriverConfig('vfs', $conf['vfs']['type']));
1092  
1093          $ts = gmmktime();
1094          $fullpath = sprintf('%s/%s/%d', IMP_VFS_LINK_ATTACH_PATH, $auth, $ts);
1095  
1096          $trailer = String::convertCharset(_("Attachments"), NLS::getCharset(), $base_part->getCharset());
1097  
1098          if ($prefs->getValue('delete_attachments_monthly')) {
1099              /* Determine the first day of the month in which the current
1100               * attachments will be ripe for deletion, then subtract 1 second
1101               * to obtain the last day of the previous month. */
1102              $del_time = gmmktime(0, 0, 0, date('n') + $prefs->getValue('delete_attachments_monthly_keep') + 1, 1, date('Y')) - 1;
1103              $trailer .= String::convertCharset(' (' . sprintf(_("Links will expire on %s"), strftime('%x', $del_time)) . ')', NLS::getCharset(), $base_part->getCharset());
1104          }
1105  
1106          foreach ($this->_cache as $att) {
1107              $trailer .= "\n" . Util::addParameter($baseurl, array('u' => $auth,
1108                                                                    't' => $ts,
1109                                                                    'f' => $att->getName()),
1110                                                    null, false);
1111              if ($conf['compose']['use_vfs']) {
1112                  $res = $vfs->rename(IMP_VFS_ATTACH_PATH, $att->getInformation('temp_filename'), $fullpath, escapeshellcmd($att->getName()));
1113              } else {
1114                  $data = file_get_contents($att->getInformation('temp_filename'));
1115                  $res = $vfs->writeData($fullpath, escapeshellcmd($att->getName()), $data, true);
1116              }
1117              if (is_a($res, 'PEAR_Error')) {
1118                  return $res;
1119              }
1120          }
1121  
1122          $this->deleteAllAttachments();
1123  
1124          if ($base_part->getPrimaryType() == 'multipart') {
1125              $mixed_part = &new MIME_Part('multipart/mixed');
1126              $mixed_part->addPart($base_part);
1127              $link_part = &new MIME_Part('text/plain', $trailer, $base_part->getCharset(), 'inline', $base_part->getCurrentEncoding());
1128              $link_part->setDescription(_("Attachment Information"));
1129              $mixed_part->addPart($link_part);
1130              return $mixed_part;
1131          } else {
1132              $base_part->appendContents("\n-----\n" . $trailer, $base_part->getCurrentEncoding());
1133              return $base_part;
1134          }
1135  
1136      }
1137  
1138  }


Généré le : Thu Nov 29 12:30:07 2007 par Balluche grâce à PHPXref 0.7
  Clicky Web Analytics