[ Index ]
 

Code source de eGroupWare 1.2.106-2

Accédez au Source d'autres logiciels libresSoutenez Angelica Josefina !

title

Body

[fermer]

/phpgwapi/inc/horde/Horde/ -> iCalendar.php (source)

   1  <?php
   2  /**
   3   * Class representing iCalendar files.
   4   *
   5   * $Horde: framework/iCalendar/iCalendar.php,v 1.53 2004/09/24 03:34:43 chuck Exp $
   6   *
   7   * Copyright 2003-2004 Mike Cochrane <mike@graftonhall.co.nz>
   8   *
   9   * See the enclosed file COPYING for license information (LGPL). If you
  10   * did not receive this file, see http://www.fsf.org/copyleft/lgpl.html.
  11   *
  12   * @author  Mike Cochrane <mike@graftonhall.co.nz>
  13   * @version $Revision: 22838 $
  14   * @since   Horde 3.0
  15   * @package Horde_iCalendar
  16   */
  17  class Horde_iCalendar {
  18  
  19      /**
  20       * The parent (containing) iCalendar object.
  21       *
  22       * @var object Horde_iCalendar $_container
  23       */
  24      var $_container = false;
  25  
  26      var $_attributes = array();
  27  
  28      var $_components = array();
  29  
  30      /**
  31       * According to RFC 2425, we should always use CRLF-terminated
  32       * lines.
  33       *
  34       * @var string $_newline
  35       */
  36      var $_newline = "\r\n";
  37  
  38      /**
  39       * Return a reference to a new component.
  40       *
  41       * @param string $type       The type of component to return
  42       * @param object $container  A container that this component
  43       *                           will be associated with.
  44       *
  45       * @return object  Reference to a Horde_iCalendar_* object as specified.
  46       */
  47      function &newComponent($type, &$container)
  48      {
  49  #        require_once 'Horde/String.php';
  50          $type = strtolower($type);
  51          $class = 'Horde_iCalendar_' . strtolower($type);
  52          if (!class_exists($class)) {
  53            include_once dirname(__FILE__) . '/iCalendar/' . $type . '.php';
  54          }
  55          if (class_exists($class)) {
  56              $component = &new $class();
  57              if ($container !== false) {
  58                  $component->_container = &$container;
  59              }
  60              return $component;
  61          } else {
  62              // Should return an dummy x-unknown type class here.
  63              return false;
  64          }
  65      }
  66  
  67      /**
  68       * Set the value of an attribute.
  69       *
  70       * @param string  $name   The name of the attribute.
  71       * @param string  $value  The value of the attribute.
  72       * @param array   $params (optional) Array containing any addition
  73       *                        parameters for this attribute.
  74       * @param boolean $append (optional) True to append the attribute, False
  75       *                        to replace the first matching attribute found.
  76       * @param array $values   (optional) array representation of $value.
  77       *                        For comma/semicolon seperated lists of values.
  78       *                        If not set use $value as single array element.
  79       */
  80      function setAttribute($name, $value, $params = array(), $append = true, $values = false)
  81      {
  82          $found = $append;
  83          if (!$values) {
  84              $values = array($value);
  85          }
  86          $keys = array_keys($this->_attributes);
  87          foreach ($keys as $key) {
  88              if ($found) break;
  89              if ($this->_attributes[$key]['name'] == $name) {
  90                  $this->_attributes[$key]['params'] = $params;
  91                  $this->_attributes[$key]['value'] = $value;
  92                  $this->_attributes[$key]['values'] = $values;
  93                  $found = true;
  94              }
  95          }
  96  
  97          if ($append || !$found) {
  98              $this->_attributes[] = array(
  99                  'name'      => $name,
 100                  'params'    => $params,
 101                  'value'     => $value,
 102                  'values'    => $values
 103              );
 104          }
 105      }
 106  
 107      /**
 108       * Sets parameter(s) for an (already existing) attribute.  The
 109       * parameter set is merged into the existing set.
 110       *
 111       * @param string $name    The name of the attribute.
 112       * @param array  $params  Array containing any additional
 113       *                        parameters for this attribute.
 114       * @return boolean  True on success, false if no attribute $name exists.
 115       */
 116      function setParameter($name, $params)
 117      {
 118          $keys = array_keys($this->_attributes);
 119          foreach ($keys as $key) {
 120              if ($this->_attributes[$key]['name'] == $name) {
 121                  $this->_attributes[$key]['params'] =
 122                      array_merge((array)$this->_attributes[$key]['params'] , $params);
 123                  return true;
 124              }
 125          }
 126  
 127          return false;
 128      }
 129  
 130      /**
 131       * Get the value of an attribute.
 132       *
 133       * @param string  $name    The name of the attribute.
 134       * @param boolean $params  Return the parameters for this attribute
 135       *                         instead of its value.
 136       *
 137       * @return mixed (object)  PEAR_Error if the attribute does not exist.
 138       *               (string)  The value of the attribute.
 139       *               (array)   The parameters for the attribute or
 140       *                         multiple values for an attribute.
 141       */
 142      function getAttribute($name, $params = false)
 143      {
 144          $result = array();
 145          foreach ($this->_attributes as $attribute) {
 146              if ($attribute['name'] == $name) {
 147                  if ($params) {
 148                      $result[] = $attribute['params'];
 149                  } else {
 150                      $result[] = $attribute['value'];
 151                  }
 152              }
 153          }
 154          if (count($result) == 0) {
 155              require_once 'PEAR.php';
 156              return PEAR::raiseError('Attribute "' . $name . '" Not Found');
 157          } if (count($result) == 1 && !$params) {
 158              return $result[0];
 159          } else {
 160              return $result;
 161          }
 162      }
 163  
 164      /**
 165       * Gets the values of an attribute as an array.  Multiple values
 166       * are possible due to:
 167       *
 168       *  a) multiplce occurences of 'name'
 169       *  b) (unsecapd) comma seperated lists.
 170       *
 171       * So for a vcard like "KEY:a,b\nKEY:c" getAttributesValues('KEY')
 172       * will return array('a','b','c').
 173       *
 174       * @param string  $name    The name of the attribute.
 175       * @return mixed (object)  PEAR_Error if the attribute does not exist.
 176       *               (array)   Multiple values for an attribute.
 177       */
 178      function getAttributeValues($name)
 179      {
 180          $result = array();
 181          foreach ($this->_attributes as $attribute) {
 182              if ($attribute['name'] == $name) {
 183                  $result = array_merge($attribute['values'], $result);
 184              }
 185          }
 186          if (!count($result)) {
 187              return PEAR::raiseError('Attribute "' . $name . '" Not Found');
 188          }
 189          return $result;
 190      }
 191  
 192      /**
 193       * Returns the value of an attribute, or a specified default value
 194       * if the attribute does not exist.
 195       *
 196       * @param string $name     The name of the attribute.
 197       * @param mixed  $default  (optional) What to return if the attribute
 198       *                         specified by $name does not exist.
 199       *
 200       * @return mixed (string) The value of $name.
 201       *               (mixed)  $default if $name does not exist.
 202       */
 203      function getAttributeDefault($name, $default = '')
 204      {
 205          $value = $this->getAttribute($name);
 206          return is_a($value, 'PEAR_Error') ? $default : $value;
 207      }
 208  
 209      /**
 210       * Remove all occurences of an attribute.
 211       *
 212       * @param string  $name   The name of the attribute.
 213       */
 214      function removeAttribute($name)
 215      {
 216          $keys = array_keys($this->_attributes);
 217          foreach ($keys as $key) {
 218              if ($this->_attributes[$key]['name'] == $name) {
 219                  unset($this->_attributes[$key]);
 220              }
 221          }
 222      }
 223  
 224      /**
 225       * Get attributes for all tags or for a given tag.
 226       *
 227       * @param string  $tag   (optional) return attributes for this tag.
 228       *                       or all attributes if not given
 229       * @return array  Array containing all the attributes and their types.
 230       */
 231      function getAllAttributes($tag = false)
 232      {
 233          if ($tag === false) {
 234              return $this->_attributes;
 235          }
 236          $result = array();
 237          foreach ($this->_attributes as $attribute) {
 238              if ($attribute['name'] == $tag) {
 239                  $result[] = $attribute;
 240              }
 241          }
 242          return $result;
 243      }
 244  
 245      /**
 246       * Add a vCalendar component (eg vEvent, vTimezone, etc.).
 247       *
 248       * @param object Horde_iCalendar $component  Component (subclass) to add.
 249       */
 250      function addComponent($component)
 251      {
 252          if (is_a($component, 'Horde_iCalendar')) {
 253              $component->_container = &$this;
 254              $this->_components[] = &$component;
 255          }
 256      }
 257  
 258      /**
 259       * Retrieve all the components.
 260       *
 261       * @return array  Array of Horde_iCalendar objects.
 262       */
 263      function getComponents()
 264      {
 265          return $this->_components;
 266      }
 267  
 268      /**
 269       * Return the classes (entry types) we have.
 270       *
 271       * @return array  Hash with class names Horde_iCalendar_xxx as keys
 272       *                and number of components of this class as value.
 273       */
 274      function getComponentClasses()
 275      {
 276          $r = array();
 277          foreach ($this->_components as $c) {
 278              $cn = strtolower(get_class($c));
 279              if (empty($r[$cn])) {
 280                  $r[$cn] = 1;
 281              } else {
 282                  $r[$cn]++;
 283              }
 284          }
 285  
 286          return $r;
 287      }
 288  
 289      /**
 290       * Number of components in this container.
 291       *
 292       * @return integer  Number of components in this container.
 293       */
 294      function getComponentCount()
 295      {
 296          return count($this->_components);
 297      }
 298  
 299      /**
 300       * Retrieve a specific component.
 301       *
 302       * @param integer $idx  The index of the object to retrieve.
 303       *
 304       * @return mixed    (boolean) False if the index does not exist.
 305       *                  (Horde_iCalendar_*) The requested component.
 306       */
 307      function getComponent($idx)
 308      {
 309          if (isset($this->_components[$idx])) {
 310              return $this->_components[$idx];
 311          } else {
 312              return false;
 313          }
 314      }
 315  
 316      /**
 317       * Locates the first child component of the specified class, and
 318       * returns a reference to this component.
 319       *
 320       * @param string $type  The type of component to find.
 321       *
 322       * @return mixed (boolean) False if no subcomponent of the specified
 323       *                         class exists.
 324       *               (Horde_iCalendar_*) A reference to the requested component.
 325       */
 326      function &findComponent($childclass)
 327      {
 328  #        require_once 'Horde/String.php';
 329  #        $childclass = 'Horde_iCalendar_' . String::lower($childclass);
 330          $childclass = 'Horde_iCalendar_' . strtolower($childclass);
 331          $keys = array_keys($this->_components);
 332          foreach ($keys as $key) {
 333              if (is_a($this->_components[$key], $childclass)) {
 334                  return $this->_components[$key];
 335              }
 336          }
 337  
 338          return false;
 339      }
 340  
 341      /**
 342       * Clears the iCalendar object (resets the components and
 343       * attributes arrays).
 344       */
 345      function clear()
 346      {
 347          $this->_components = array();
 348          $this->_attributes = array();
 349      }
 350  
 351      /**
 352       * Export as vCalendar format.
 353       */
 354      function exportvCalendar()
 355      {
 356          // Default values.
 357          $requiredAttributes['VERSION'] = '2.0';
 358          $requiredAttributes['PRODID'] = '-//The Horde Project//Horde_iCalendar Library, Horde 3.0-cvs //EN';
 359          $requiredAttributes['METHOD'] = 'PUBLISH';
 360  
 361          foreach ($requiredAttributes as $name => $default_value) {
 362              if (is_a($this->getattribute($name), 'PEAR_Error')) {
 363                  $this->setAttribute($name, $default_value);
 364              }
 365          }
 366  
 367          return $this->_exportvData('VCALENDAR') . $this->_newline;
 368      }
 369  
 370      /**
 371       * Export this entry as a hash array with tag names as keys.
 372       *
 373       * @param boolean (optional) $paramsInKeys
 374       *                If false, the operation can be quite lossy as the
 375       *                parameters are ignored when building the array keys.
 376       *                So if you export a vcard with
 377       *                LABEL;TYPE=WORK:foo
 378       *                LABEL;TYPE=HOME:bar
 379       *                the resulting hash contains only one label field!
 380       *                If set to true, array keys look like 'LABEL;TYPE=WORK'
 381       * @return array  A hash array with tag names as keys.
 382       */
 383      function toHash($paramsInKeys = false)
 384      {
 385          $hash = array();
 386          foreach ($this->_attributes as $a)  {
 387              $k = $a['name'];
 388              if ($paramsInKeys && is_array($a['params'])) {
 389                  foreach ($a['params'] as $p => $v) {
 390                      $k .= ";$p=$v";
 391                  }
 392              }
 393              $hash[$k] = $a['value'];
 394          }
 395  
 396          return $hash;
 397      }
 398  
 399      /**
 400       * Parse a string containing vCalendar data.
 401       *
 402       * @param string  $text  The data to parse.
 403       * @param string  $base  The type of the base object.
 404       * @param string  $charset (optional) The encoding charset for $text. Defaults to utf-8
 405       * @param boolean $clear (optional) True to clear() the iCal object before parsing.
 406       *
 407       * @return boolean  True on successful import, false otherwise.
 408       */
 409      function parsevCalendar($text, $base = 'VCALENDAR', $charset = 'utf-8', $clear = true)
 410      {
 411          if ($clear) {
 412              $this->clear();
 413          }
 414          if (preg_match('/(BEGIN:' . $base . '\r?\n)([\W\w]*)(END:' . $base . '\r?\n?)/i', $text, $matches)) {
 415              $vCal = $matches[2];
 416          } else {
 417              // Text isn't enclosed in BEGIN:VCALENDAR
 418              // .. END:VCALENDAR. We'll try to parse it anyway.
 419              $vCal = $text;
 420          }
 421  
 422          // All subcomponents.
 423          $matches = null;
 424          if (preg_match_all('/BEGIN:([\S]*)(\r\n|\r|\n)([\W\w]*)END:\1(\r\n|\r|\n)/U', $vCal, $matches)) {
 425              foreach ($matches[0] as $key => $data) {
 426                  $type = $matches[1][$key];
 427                  $component = &Horde_iCalendar::newComponent(trim($type), $this);
 428                  if ($component === false) {
 429                      return PEAR::raiseError("Unable to create object for type $type");
 430                  }
 431                  $component->parsevCalendar($data);
 432  
 433                  $this->addComponent($component);
 434  
 435                  // Remove from the vCalendar data.
 436                  $vCal = str_replace($data, '', $vCal);
 437              }
 438          }
 439  
 440          // Unfold any folded lines.
 441          #$vCal = preg_replace ('/(\r|\n)+ /', ' ', $vCal);
 442  
 443          // Unfold "quoted printable" folded lines like:
 444          //  BODY;ENCODING=QUOTED-PRINTABLE:=
 445          //  another=20line=
 446          //  last=20line
 447  #        Horde::logMessage("SymcML: match 1", __FILE__, __LINE__, PEAR_LOG_DEBUG);
 448  #        if (preg_match_all('/^([^:]+;\s*ENCODING=QUOTED-PRINTABLE(.*=[\r\n|\r|\n])+(.*[^=])[\r\n|\r|\n])/mU', $vCal, $matches)) {
 449  ##        if (preg_match_all('/^(BODY;ENCODING=QUOTED-PRINTABLE(.*=\r\n)+(.*)?\r?\n)/mU', $vCal, $matches)) {
 450  #        Horde::logMessage("SymcML: match 2", __FILE__, __LINE__, PEAR_LOG_DEBUG);
 451  #            foreach ($matches[1] as $s) {
 452  #            Horde::logMessage("SymcML: match 3 $s", __FILE__, __LINE__, PEAR_LOG_DEBUG);
 453  #                $r = preg_replace('/=[\r\n|\r|\n]/', '', $s);
 454  #            Horde::logMessage("SymcML: match 4 $r", __FILE__, __LINE__, PEAR_LOG_DEBUG);
 455  #                $vCal = str_replace($s, $r, $vCal);
 456  #            }
 457  #        }
 458  
 459          // Unfold "quoted printable" folded lines like:
 460          //  BODY;ENCODING=QUOTED-PRINTABLE:=
 461          //  another=20line=
 462          //  last=20line
 463          #if (preg_match_all('/^([^:]+;\s*ENCODING=QUOTED-PRINTABLE(.*=*\s))/mU', $vCal, $matches)) {
 464      #    $matches = preg_split('/=+\s/',$vCal);
 465      #    $vCal = implode('',$matches);
 466          #}
 467          if (preg_match_all('/^([^:]+;\s*ENCODING=QUOTED-PRINTABLE(.*=*\s))/mU', $vCal, $matches)) {
 468          $matches = preg_split('/=(\r\n|\r|\n)/',$vCal);
 469          $vCal = implode('',$matches);
 470          }
 471  
 472          // Parse the remaining attributes.
 473  
 474          if (preg_match_all('/(.*):([^\r\n]*)[\r\n]+/', $vCal, $matches)) {
 475              foreach ($matches[0] as $attribute) {
 476                  preg_match('/([^;^:]*)((;[^:]*)?):([^\r\n]*)[\r\n]*/', $attribute, $parts);
 477                  $tag = $parts[1];
 478                  $value = $parts[4];
 479                  $params = array();
 480  
 481                  // Parse parameters.
 482                  if (!empty($parts[2])) {
 483                      preg_match_all('/;(([^;=]*)(=([^;]*))?)/', $parts[2], $param_parts);
 484                      foreach ($param_parts[2] as $key => $paramName) {
 485                          $paramValue = $param_parts[4][$key];
 486                          $params[$paramName] = $paramValue;
 487                      }
 488                  }
 489  
 490                  // Charset and encoding handling.
 491                  if ((isset($params['ENCODING'])
 492                       && $params['ENCODING'] == 'QUOTED-PRINTABLE')
 493                      || isset($params['QUOTED-PRINTABLE'])) {
 494  
 495                      $value = quoted_printable_decode($value);
 496                  }
 497  
 498                  if (isset($params['CHARSET'])) {
 499                      $value = $GLOBALS['egw']->translation->convert($value, $params['CHARSET']);
 500                  } else {
 501                      // As per RFC 2279, assume UTF8 if we don't have
 502                      // an explicit charset parameter.
 503                      $value = $GLOBALS['egw']->translation->convert($value, 'utf-8');
 504                  }
 505  
 506                  switch ($tag) {
 507                  // Date fields.
 508                  case 'DTSTAMP':
 509                  case 'COMPLETED':
 510                  case 'CREATED':
 511                  case 'LAST-MODIFIED':
 512                  case 'BDAY':
 513                      $this->setAttribute($tag, $this->_parseDateTime($value), $params);
 514                      break;
 515  
 516                  case 'DTEND':
 517                  case 'DTSTART':
 518                  case 'DUE':
 519                  case 'RECURRENCE-ID':
 520                      if (isset($params['VALUE']) && $params['VALUE'] == 'DATE') {
 521                          $this->setAttribute($tag, $this->_parseDate($value), $params);
 522                      } else {
 523                          $this->setAttribute($tag, $this->_parseDateTime($value), $params);
 524                      }
 525                      break;
 526  
 527                  case 'RDATE':
 528                      if (isset($params['VALUE'])) {
 529                          if ($params['VALUE'] == 'DATE') {
 530                              $this->setAttribute($tag, $this->_parseDate($value), $params);
 531                          } elseif ($params['VALUE'] == 'PERIOD') {
 532                              $this->setAttribute($tag, $this->_parsePeriod($value), $params);
 533                          } else {
 534                              $this->setAttribute($tag, $this->_parseDateTime($value), $params);
 535                          }
 536                      } else {
 537                          $this->setAttribute($tag, $this->_parseDateTime($value), $params);
 538                      }
 539                      break;
 540  
 541                  case 'TRIGGER':
 542                      if (isset($params['VALUE'])) {
 543                          if ($params['VALUE'] == 'DATE-TIME') {
 544                              $this->setAttribute($tag, $this->_parseDateTime($value), $params);
 545                          } else {
 546                              $this->setAttribute($tag, $this->_parseDuration($value), $params);
 547                          }
 548                      } else {
 549                          $this->setAttribute($tag, $this->_parseDuration($value), $params);
 550                      }
 551                      break;
 552  
 553                  // Comma seperated dates.
 554                  case 'EXDATE':
 555                      $values = array();
 556                      $dates = array();
 557                      preg_match_all('/;([^;]*)/', ';' . $value, $values);
 558  
 559                      foreach ($values[1] as $value) {
 560                          if (isset($params['VALUE'])) {
 561                              if ($params['VALUE'] == 'DATE-TIME') {
 562                                  $dates[] = $this->_parseDateTime($value);
 563                              } elseif ($params['VALUE'] == 'DATE') {
 564                                  $dates[] = $this->_parseDate($value);
 565                              }
 566                          } else {
 567                              $dates[] = $this->_parseDateTime($value);
 568                          }
 569                      }
 570                      $this->setAttribute($tag, $dates, $params);
 571                      break;
 572  
 573                  // Duration fields.
 574                  case 'DURATION':
 575                      $this->setAttribute($tag, $this->_parseDuration($value), $params);
 576                      break;
 577  
 578                  // Period of time fields.
 579                  case 'FREEBUSY':
 580                      $values = array();
 581                      $periods = array();
 582                      preg_match_all('/,([^,]*)/', ',' . $value, $values);
 583                      foreach ($values[1] as $value) {
 584                          $periods[] = $this->_parsePeriod($value);
 585                      }
 586  
 587                      $this->setAttribute($tag, $periods, $params);
 588                      break;
 589  
 590                  // UTC offset fields.
 591                  case 'TZOFFSETFROM':
 592                  case 'TZOFFSETTO':
 593                      $this->setAttribute($tag, $this->_parseUtcOffset($value), $params);
 594                      break;
 595  
 596                  // Integer fields.
 597                  case 'PERCENT-COMPLETE':
 598                  case 'PRIORITY':
 599                  case 'REPEAT':
 600                  case 'SEQUENCE':
 601                      $this->setAttribute($tag, intval($value), $params);
 602                      break;
 603  
 604                  // Geo fields.
 605                  case 'GEO':
 606                      $floats = split(';', $value);
 607                      $value['latitude'] = floatval($floats[0]);
 608                      $value['longitude'] = floatval($floats[1]);
 609                      $this->setAttribute($tag, $value, $params);
 610                      break;
 611  
 612                  // Recursion fields.
 613                  case 'EXRULE':
 614                  case 'RRULE':
 615                      $this->setAttribute($tag, trim($value), $params);
 616                      break;
 617  
 618                  // ADR an N are lists seperated by unescaped semi-colons.
 619                  case 'ADR':
 620                  case 'N':
 621                  case 'ORG':
 622  
 623                      $value = trim($value);
 624                      // As of rfc 2426 2.4.2 semi-colon, comma, and
 625                      // colon must be escaped.
 626                      $value = str_replace('\\n', $this->_newline, $value);
 627                      $value = str_replace('\\,', ',', $value);
 628                      $value = str_replace('\\:', ':', $value);
 629  
 630                      // Split by unescaped semi-colons:
 631                      $values = preg_split('/(?<!\\\\);/',$value);
 632                      $value = str_replace('\\;', ';', $value);
 633                      $values = str_replace('\\;', ';', $values);
 634                      $this->setAttribute($tag, trim($value), $params, true, $values);
 635  
 636                      break;
 637  
 638                  // String fields.
 639                  default:
 640                      $value = trim($value);
 641                      // As of rfc 2426 2.4.2 semi-colon, comma, and
 642                      // colon must be escaped.
 643                      $value = str_replace('\\n', $this->_newline, $value);
 644                      $value = str_replace('\\;', ';', $value);
 645                      $value = str_replace('\\:', ':', $value);
 646  
 647                      // Split by unescaped commas:
 648                      $values = preg_split('/(?<!\\\\),/',$value);
 649                      $value = str_replace('\\,', ',', $value);
 650                      $values = str_replace('\\,', ',', $values);
 651  
 652                      $this->setAttribute($tag, trim($value), $params, true, $values);
 653                      break;
 654                  }
 655              }
 656          }
 657  
 658          return true;
 659      }
 660  
 661      /**
 662       * Export this component in vCal format.
 663       *
 664       * @param string $base  (optional) The type of the base object.
 665       *
 666       * @return string  vCal format data.
 667       */
 668      function _exportvData($base = 'VCALENDAR')
 669      {
 670          $result  = 'BEGIN:' . strtoupper($base) . $this->_newline;
 671  
 672          // Ensure that version is the first attribute.
 673          $v = $this->getAttributeDefault('VERSION', false);
 674          if ($v) {
 675              $result .= 'VERSION:' . $v. $this->_newline;
 676          }
 677  
 678          foreach ($this->_attributes as $attribute) {
 679              $name = $attribute['name'];
 680              if ($name == 'VERSION') {
 681                  // Already done.
 682                  continue;
 683              }
 684  
 685              $params = $attribute['params'];
 686              $params_str = '';
 687  
 688              if (count($params)) {
 689                  foreach ($params as $param_name => $param_value) {
 690                      $params_str .= ";$param_name=$param_value";
 691                  }
 692              }
 693  
 694              $value = $attribute['value'];
 695  
 696              switch ($name) {
 697              // Date fields.
 698              case 'DTSTAMP':
 699              case 'COMPLETED':
 700              case 'CREATED':
 701              case 'DCREATED':
 702              case 'LAST-MODIFIED':
 703                  $value = $this->_exportDateTime($value);
 704                  break;
 705  
 706              case 'DTEND':
 707              case 'DTSTART':
 708              case 'DUE':
 709              case 'RECURRENCE-ID':
 710                  if (isset($params['VALUE'])) {
 711                      if ($params['VALUE'] == 'DATE') {
 712                          $value = $this->_exportDate($value);
 713                      } else {
 714                          $value = $this->_exportDateTime($value);
 715                      }
 716                  } else {
 717                      $value = $this->_exportDateTime($value);
 718                  }
 719                  break;
 720  
 721              case 'RDATE':
 722                  if (isset($params['VALUE'])) {
 723                      if ($params['VALUE'] == 'DATE') {
 724                          $value = $this->_exportDate($value);
 725                      } elseif ($params['VALUE'] == 'PERIOD') {
 726                          $value = $this->_exportPeriod($value);
 727                      } else {
 728                          $value = $this->_exportDateTime($value);
 729                      }
 730                  } else {
 731                      $value = $this->_exportDateTime($value);
 732                  }
 733                  break;
 734  
 735              case 'TRIGGER':
 736                  if (isset($params['VALUE'])) {
 737                      if ($params['VALUE'] == 'DATE-TIME') {
 738                          $value = $this->_exportDateTime($value);
 739                      } elseif ($params['VALUE'] == 'DURATION') {
 740                          $value = $this->_exportDuration($value);
 741                      }
 742                  } else {
 743                      $value = $this->_exportDuration($value);
 744                  }
 745                  break;
 746  
 747              // Duration fields.
 748              case 'DURATION':
 749                  $value = $this->_exportDuration($value);
 750                  break;
 751  
 752              // Period of time fields.
 753              case 'FREEBUSY':
 754                  $value_str = '';
 755                  foreach ($value as $period) {
 756                      $value_str .= empty($value_str) ? '' : ',';
 757                      $value_str .= $this->_exportPeriod($period);
 758                  }
 759                  $value = $value_str;
 760                  break;
 761  
 762              // UTC offset fields.
 763              case 'TZOFFSETFROM':
 764              case 'TZOFFSETTO':
 765                  $value = $this->_exportUtcOffset($value);
 766                  break;
 767  
 768              // Integer fields.
 769              case 'PERCENT-COMPLETE':
 770              case 'PRIORITY':
 771              case 'REPEAT':
 772              case 'SEQUENCE':
 773                  $value = "$value";
 774                  break;
 775  
 776              // Geo fields.
 777              case 'GEO':
 778                  $value = $value['latitude'] . ',' . $value['longitude'];
 779                  break;
 780  
 781              // Recurrence fields.
 782              case 'EXRULE':
 783              case 'RRULE':
 784  
 785          //Text Fields
 786          case 'SUMMARY':
 787          case 'DESCRIPTION':
 788          case 'COMMENT':
 789          $value = str_replace('\\', '\\\\', $value);
 790          $value = str_replace($this->_newline, '\n', $value);
 791          $value = str_replace(',', '\,', $value);
 792          $value = str_replace(';', '\;', $value);
 793          $value = str_replace(':', '\:', $value);
 794                  break;
 795          
 796              default:
 797                  break;
 798              }
 799  
 800              if (!empty($params['ENCODING']) &&
 801                  $params['ENCODING'] == 'QUOTED-PRINTABLE' && strlen(trim($value)) > 0) {
 802                  $value = str_replace("\r", '', $value);
 803  #                $result .= "$name$params_str:=" . $this->_newline
 804  #                    . $this->_quotedPrintableEncode($value)
 805  #                    . $this->_newline;
 806                  $result .= "$name$params_str:"
 807                      . $this->_quotedPrintableEncode($value)
 808                      . $this->_newline;
 809              } else {
 810  # JVL: prevent : for empty values
 811  #                $attr_string = "$name$params_str:$value";  
 812                  $attr_string = "$name$params_str";
 813          $attr_string .= (!empty($value)) ? ":$value" : ';';
 814  
 815                  $result .= $this->_foldLine($attr_string) . $this->_newline;
 816              }
 817          }
 818  
 819          foreach ($this->getComponents() as $component) {
 820              $result .= $component->exportvCalendar() . $this->_newline;
 821          }
 822  
 823          $result .= 'END:' . $base;
 824  
 825          return $result;
 826      }
 827  
 828      /**
 829       * Parse a UTC Offset field.
 830       */
 831      function _parseUtcOffset($text)
 832      {
 833          $offset = array();
 834          if (preg_match('/(\+|-)([0-9]{2})([0-9]{2})([0-9]{2})?/', $text, $timeParts)) {
 835              $offset['ahead']  = (boolean)($timeParts[1] == '+');
 836              $offset['hour']   = intval($timeParts[2]);
 837              $offset['minute'] = intval($timeParts[3]);
 838              if (isset($timeParts[4])) {
 839                  $offset['second'] = intval($timeParts[4]);
 840              }
 841              return $offset;
 842          } else {
 843              return false;
 844          }
 845      }
 846  
 847      /**
 848       * Export a UTC Offset field.
 849       */
 850      function _exportUtcOffset($value)
 851      {
 852          $offset = $value['ahead'] ? '+' : '-';
 853          $offset .= sprintf('%02d%02d',
 854                             $value['hour'], $value['minute']);
 855          if (isset($value['second'])) {
 856              $offset .= sprintf('%02d', $value['second']);
 857          }
 858  
 859          return $offset;
 860      }
 861  
 862      /**
 863       * Parse a Time Period field.
 864       */
 865      function _parsePeriod($text)
 866      {
 867          $periodParts = split('/', $text);
 868  
 869          $start = $this->_parseDateTime($periodParts[0]);
 870  
 871          if ($duration = $this->_parseDuration($periodParts[1])) {
 872              return array('start' => $start, 'duration' => $duration);
 873          } elseif ($end = $this->_parseDateTime($periodParts[1])) {
 874              return array('start' => $start, 'end' => $end);
 875          }
 876      }
 877  
 878      /**
 879       * Export a Time Period field.
 880       */
 881      function _exportPeriod($value)
 882      {
 883          $period = $this->_exportDateTime($value['start']);
 884          $period .= '/';
 885          if (isset($value['duration'])) {
 886              $period .= $this->_exportDuration($value['duration']);
 887          } else {
 888              $period .= $this->_exportDateTime($value['end']);
 889          }
 890          return $period;
 891      }
 892  
 893      /**
 894       * Parse a DateTime field into a unix timestamp.
 895       */
 896      function _parseDateTime($text)
 897      {
 898          $dateParts = split('T', $text);
 899          if (count($dateParts) != 2 && !empty($text)) {
 900              // Not a datetime field but may be just a date field.
 901              if (!$date = $this->_parseDate($text)) {
 902                  return $date;
 903              }
 904              return @gmmktime(0, 0, 0, $date['month'], $date['mday'], $date['year']);
 905          }
 906  
 907          if (!$date = $this->_parseDate($dateParts[0])) {
 908              return $date;
 909          }
 910          if (!$time = $this->_parseTime($dateParts[1])) {
 911              return $time;
 912          }
 913  
 914          if ($time['zone'] == 'UTC') {
 915              return @gmmktime($time['hour'], $time['minute'], $time['second'],
 916                               $date['month'], $date['mday'], $date['year']);
 917          } else {
 918              return @mktime($time['hour'], $time['minute'], $time['second'],
 919                             $date['month'], $date['mday'], $date['year']);
 920          }
 921      }
 922  
 923      /**
 924       * Export a DateTime field.
 925       */
 926      function _exportDateTime($value)
 927      {
 928          $temp = array();
 929          if (!is_object($value) || is_array($value)) {
 930              $TZOffset  = 3600 * substr(date('O',$value), 0, 3);
 931              $TZOffset += 60 * substr(date('O',$value), 3, 2);
 932              $value -= $TZOffset;
 933  
 934              $temp['zone']   = 'UTC';
 935              $temp['year']   = date('Y', $value);
 936              $temp['month']  = date('n', $value);
 937              $temp['mday']   = date('j', $value);
 938              $temp['hour']   = date('G', $value);
 939              $temp['minute'] = date('i', $value);
 940              $temp['second'] = date('s', $value);
 941          } else {
 942              $dateOb = (object)$value;
 943  
 944              $TZOffset = date('O',mktime($dateOb->hour,$dateOb->min,$dateOb->sec,$dateOb->month,$dateOb->mday,$dateOb->year));
 945  
 946              // Minutes.
 947              $TZOffsetMin = substr($TZOffset, 0, 1) . substr($TZOffset, 3, 2);
 948              $thisMin = $dateOb->min - $TZOffsetMin;
 949  
 950              // Hours.
 951              $TZOffsetHour = substr($TZOffset, 0, 3);
 952              $thisHour = $dateOb->hour - $TZOffsetHour;
 953  
 954              if ($thisMin < 0) {
 955                  $thisHour -= 1;
 956                  $thisMin += 60;
 957              }
 958  
 959              if ($thisHour < 0) {
 960                  require_once 'Date/Calc.php';
 961                  $prevday = Date_Calc::prevDay($dateOb->mday, $dateOb->month, $dateOb->year);
 962                  $dateOb->mday  = substr($prevday, 6, 2);
 963                  $dateOb->month = substr($prevday, 4, 2);
 964                  $dateOb->year  = substr($prevday, 0, 4);
 965                  $thisHour += 24;
 966              }
 967  
 968              $temp['zone']   = 'UTC';
 969              $temp['year']   = $dateOb->year;
 970              $temp['month']  = $dateOb->month;
 971              $temp['mday']   = $dateOb->mday;
 972              $temp['hour']   = $thisHour;
 973              $temp['minute'] = $dateOb->min;
 974              $temp['second'] = $dateOb->sec;
 975          }
 976  
 977          return Horde_iCalendar::_exportDate($temp) . 'T' . Horde_iCalendar::_exportTime($temp);
 978      }
 979  
 980      /**
 981       * Parse a Time field.
 982       */
 983      function _parseTime($text)
 984      {
 985          if (preg_match('/([0-9]{2})([0-9]{2})([0-9]{2})(Z)?/', $text, $timeParts)) {
 986              $time['hour'] = intval($timeParts[1]);
 987              $time['minute'] = intval($timeParts[2]);
 988              $time['second'] = intval($timeParts[3]);
 989              if (isset($timeParts[4])) {
 990                  $time['zone'] = 'UTC';
 991              } else {
 992                  $time['zone'] = 'Local';
 993              }
 994              return $time;
 995          } else {
 996              return false;
 997          }
 998      }
 999  
1000      /**
1001       * Export a Time field.
1002       */
1003      function _exportTime($value)
1004      {
1005          $time = sprintf('%02d%02d%02d',
1006                          $value['hour'], $value['minute'], $value['second']);
1007          if ($value['zone'] == 'UTC') {
1008              $time .= 'Z';
1009          }
1010          return $time;
1011      }
1012  
1013      /**
1014       * Parse a Date field.
1015       */
1016      function _parseDate($text)
1017      {
1018          if (strlen($text) != 8) {
1019              return false;
1020          }
1021  
1022          $date['year']  = intval(substr($text, 0, 4));
1023          $date['month'] = intval(substr($text, 4, 2));
1024          $date['mday']  = intval(substr($text, 6, 2));
1025  
1026          return $date;
1027      }
1028  
1029      /**
1030       * Export a Date field.
1031       */
1032      function _exportDate($value)
1033      {
1034          return sprintf('%04d%02d%02d',
1035                         $value['year'], $value['month'], $value['mday']);
1036      }
1037  
1038      /**
1039       * Parse a Duration Value field.
1040       */
1041      function _parseDuration($text)
1042      {
1043          if (preg_match('/([+]?|[-])P(([0-9]+W)|([0-9]+D)|)(T(([0-9]+H)|([0-9]+M)|([0-9]+S))+)?/', trim($text), $durvalue)) {
1044              // Weeks.
1045              $duration = 7 * 86400 * intval($durvalue[3]);
1046  
1047              if (count($durvalue) > 4) {
1048                  // Days.
1049                  $duration += 86400 * intval($durvalue[4]);
1050              }
1051              if (count($durvalue) > 5) {
1052                  // Hours.
1053                  $duration += 3600 * intval($durvalue[7]);
1054  
1055                  // Mins.
1056                  if (isset($durvalue[8])) {
1057                      $duration += 60 * intval($durvalue[8]);
1058                  }
1059  
1060                  // Secs.
1061                  if (isset($durvalue[9])) {
1062                      $duration += intval($durvalue[9]);
1063                  }
1064              }
1065  
1066              // Sign.
1067              if ($durvalue[1] == "-") {
1068                  $duration *= -1;
1069              }
1070  
1071              return $duration;
1072          } else {
1073              return false;
1074          }
1075      }
1076  
1077      /**
1078       * Export a duration value.
1079       */
1080      function _exportDuration($value)
1081      {
1082          $duration = '';
1083          if ($value < 0) {
1084              $value *= -1;
1085              $duration .= '-';
1086          }
1087          $duration .= 'P';
1088  
1089          $weeks = floor($value / (7 * 86400));
1090          $value = $value % (7 * 86400);
1091          if ($weeks) {
1092              $duration .= $weeks . 'W';
1093          }
1094  
1095          $days = floor($value / (86400));
1096          $value = $value % (86400);
1097          if ($days) {
1098              $duration .= $days . 'D';
1099          }
1100  
1101          if ($value) {
1102              $duration .= 'T';
1103  
1104              $hours = floor($value / 3600);
1105              $value = $value % 3600;
1106              if ($hours) {
1107                  $duration .= $hours . 'H';
1108              }
1109  
1110              $mins = floor($value / 60);
1111              $value = $value % 60;
1112              if ($mins) {
1113                  $duration .= $mins . 'M';
1114              }
1115  
1116              if ($value) {
1117                  $duration .= $value . 'S';
1118              }
1119          }
1120  
1121          return $duration;
1122      }
1123  
1124      /**
1125       * Return the folded version of a line.
1126       * JVL rewritten to fold on any ; or: or = if present before column 75
1127       * this is still rfc2445 section 4.1 compliant
1128       */
1129      function _foldLine($line)
1130      {
1131          $line = preg_replace("/\r\n|\n|\r/", '\n', $line);
1132          if (strlen($line) > 75) {
1133              $foldedline = '';
1134              while (!empty($line)) {
1135                $maxLine = substr($line, 0, 75);
1136                $cutPoint = 1+max(is_numeric($p1 = strrpos($maxLine,';')) ? $p1 : -1,
1137                          is_numeric($p1 = strrpos($maxLine,':')) ? $p1 : -1,
1138                          is_numeric($p1 = strrpos($maxLine,'=')) ? $p1 : -1);
1139                if ($cutPoint <  1)  // nothing found, then fold complete maxLine
1140                  $cutPoint = 75;
1141                // now fold [0..(cutPoint-1)]
1142                $foldedline .= (empty($foldedline))
1143                  ?   substr($line, 0, $cutPoint)
1144                  :  $this->_newline . ' ' . substr($line, 0, $cutPoint);
1145                
1146                $line = (strlen($line) <= $cutPoint)
1147                  ? ''
1148                  : substr($line, $cutPoint);
1149           
1150                if (strlen($line) < 75) {
1151                  $foldedline .=  $this->_newline . ' ' . $line;
1152                  $line = '';
1153                }
1154  
1155              }
1156              return $foldedline;
1157          }
1158          return $line;
1159      }
1160  
1161      /**
1162       * Convert an 8bit string to a quoted-printable string according
1163       * to RFC2045, section 6.7.
1164       *
1165       * Uses imap_8bit if available.
1166       *
1167       * @param  string $input  The string to be encoded.
1168       *
1169       * @return string         The quoted-printable encoded string.
1170       */
1171      function _quotedPrintableEncode($input = '')
1172      {
1173          return $this->EncodeQP($input);
1174      
1175      #$input = preg_replace('!(\r\n|\r|\n)!',"\n",$input);
1176  
1177          // If imap_8bit() is available, use it.
1178          if (function_exists('imap_8bit')) {
1179              $retValue = imap_8bit($input);
1180          #$retValue = preg_replace('/=0A/',"=0D=0A=\r\n",$retValue);
1181          return $retValue;
1182          }
1183  
1184          // Rather dumb replacment: just encode everything.
1185          $hex = array('0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
1186                       'A', 'B', 'C', 'D', 'E', 'F');
1187  
1188          $output = '';
1189          $len = strlen($input);
1190          for ($i = 0; $i < $len; ++$i) {
1191              $c = substr($input, $i, 1);
1192              $dec = ord($c);
1193              $output .= '=' . $hex[floor($dec / 16)] . $hex[floor($dec % 16)];
1194              if (($i + 1) % 25 == 0) {
1195                  $output .= "=\r\n";
1196              }
1197          }
1198          return $output;
1199      }
1200      var $LE              = "\r\n";
1201  
1202      /**
1203       * Encode string to quoted-printable.  
1204       * @access private
1205       * @return string
1206       */
1207      function EncodeQP_old ($str) {
1208          $encoded = $this->FixEOL($str);
1209          #$encoded = $str;
1210          #if (substr($encoded, -(strlen($this->LE))) != $this->LE)
1211          #    $encoded .= $this->LE;
1212  
1213          // Replace every high ascii, control and = characters
1214          #$encoded = preg_replace('/([\000-\010\013\014\016-\037\075\177-\377])/e',
1215          #          "'='.sprintf('%02X', ord('\\1'))", $encoded);
1216          $encoded = preg_replace('/([\000-\012\015\016\020-\037\075\177-\377])/e',
1217                    "'='.sprintf('%02X', ord('\\1'))", $encoded);
1218          // Replace every spaces and tabs when it's the last character on a line
1219          #$encoded = preg_replace("/([\011\040])".$this->LE."/e",
1220          #          "'='.sprintf('%02X', ord('\\1')).'".$this->LE."'", $encoded);
1221          $encoded = preg_replace("/([\011\040])".$this->LE."/e",
1222                    "'='.sprintf('%02X', ord('\\1')).'".$this->LE."'", $encoded);
1223  
1224          // Maximum line length of 76 characters before CRLF (74 + space + '=')
1225          $encoded = $this->WrapText($encoded, 74, true);
1226  
1227          return $encoded;
1228      }
1229  
1230      /**
1231       * Wraps message for use with mailers that do not
1232       * automatically perform wrapping and for quoted-printable.
1233       * Original written by philippe.  
1234       * @access private
1235       * @return string
1236       */
1237      function WrapText_old($message, $length, $qp_mode = false) {
1238          $soft_break = ($qp_mode) ? "=\r\n" : $this->LE;
1239  
1240          #$message = $this->FixEOL($message);
1241          if (substr($message, -1) == $this->LE)
1242              $message = substr($message, 0, -1);
1243  
1244          $line = explode("=0D=0A", $message);
1245          $message = "";
1246          for ($i=0 ;$i < count($line); $i++)
1247          {
1248            $line_part = explode(" ", $line[$i]);
1249            $buf = "";
1250            for ($e = 0; $e<count($line_part); $e++)
1251            {
1252                $word = $line_part[$e];
1253                if ($qp_mode and (strlen($word) > $length))
1254                {
1255                  $space_left = $length - strlen($buf) - 1;
1256                  if ($e != 0)
1257                  {
1258                      if ($space_left > 20)
1259                      {
1260                          $len = $space_left;
1261                          if (substr($word, $len - 1, 1) == "=")
1262                            $len--;
1263                          elseif (substr($word, $len - 2, 1) == "=")
1264                            $len -= 2;
1265                          $part = substr($word, 0, $len);
1266                          $word = substr($word, $len);
1267                          $buf .= " " . $part;
1268                          $message .= $buf . sprintf("=%s", $this->LE);
1269                      }
1270                      else
1271                      {
1272                          $message .= $buf . $soft_break;
1273                      }
1274                      $buf = "";
1275                  }
1276                  while (strlen($word) > 0)
1277                  {
1278                      $len = $length;
1279                      if (substr($word, $len - 1, 1) == "=")
1280                          $len--;
1281                      elseif (substr($word, $len - 2, 1) == "=")
1282                          $len -= 2;
1283                      $part = substr($word, 0, $len);
1284                      $word = substr($word, $len);
1285  
1286                      if (strlen($word) > 0)
1287                          $message .= $part . sprintf("=%s", $this->LE);
1288                      else
1289                          $buf = $part;
1290                  }
1291                }
1292                else
1293                {
1294                  $buf_o = $buf;
1295                  $buf .= ($e == 0) ? $word : (" " . $word); 
1296  
1297                  if (strlen($buf) > $length and $buf_o != "")
1298                  {
1299                      $message .= $buf_o . $soft_break;
1300                      $buf = $word;
1301                  }
1302                }
1303            }
1304            $message .= $buf;
1305            if((count($line)-1) > $i)
1306                $message .= "=0D=0A=\r\n";
1307          }
1308  
1309          return $message;
1310      }
1311      /**
1312       * Changes every end of line from CR or LF to CRLF.  
1313       * @access private
1314       * @return string
1315       */
1316      function FixEOL($str) {
1317            $str = str_replace("\r\n", "\n", $str);
1318          $str = str_replace("\r", "\n", $str);
1319          $str = str_replace("\n", $this->LE, $str);
1320          return $str;
1321      }
1322  
1323      /**
1324       * Encode string to quoted-printable.  
1325       * @access private
1326       * @return string
1327       */
1328      function EncodeQP ($str) {
1329          $encoded = $this->FixEOL($str);
1330          # see bugreport http://sourceforge.net/tracker/index.php?func=detail&aid=1536674&group_id=78745&atid=554338
1331          //if (substr($encoded, -(strlen($this->LE))) != $this->LE)
1332          //    $encoded .= $this->LE;
1333  
1334          // Replace every high ascii, control and = characters
1335          #$encoded = preg_replace('/([\000-\010\013\014\016-\037\075\177-\377])/e',
1336          #          "'='.sprintf('%02X', ord('\\1'))", $encoded);
1337          $encoded = preg_replace('/([\000-\012\015\016\020-\037\075\177-\377])/e',
1338                    "'='.sprintf('%02X', ord('\\1'))", $encoded);
1339          // Replace every spaces and tabs when it's the last character on a line
1340          $encoded = preg_replace("/([\011\040])".$this->LE."/e",
1341                    "'='.sprintf('%02X', ord('\\1')).'".$this->LE."'", $encoded);
1342  
1343          // Maximum line length of 76 characters before CRLF (74 + space + '=')
1344          #$encoded = $this->WrapText($encoded, 74, true);
1345  
1346          return $encoded;
1347      }
1348  
1349      /**
1350       * Wraps message for use with mailers that do not
1351       * automatically perform wrapping and for quoted-printable.
1352       * Original written by philippe.  
1353       * @access private
1354       * @return string
1355       */
1356      function WrapText($message, $length, $qp_mode = false) {
1357          $soft_break = ($qp_mode) ? sprintf(" =%s", $this->LE) : $this->LE;
1358          $soft_break = "..=";
1359  
1360          $message = $this->FixEOL($message);
1361          if (substr($message, -1) == $this->LE)
1362              $message = substr($message, 0, -1);
1363  
1364          $line = explode($this->LE, $message);
1365          $message = "";
1366          for ($i=0 ;$i < count($line); $i++)
1367          {
1368            $line_part = explode(" ", $line[$i]);
1369            $buf = "";
1370            for ($e = 0; $e<count($line_part); $e++)
1371            {
1372                $word = $line_part[$e];
1373                if ($qp_mode and (strlen($word) > $length))
1374                {
1375                  $space_left = $length - strlen($buf) - 1;
1376                  if ($e != 0)
1377                  {
1378                      if ($space_left > 20)
1379                      {
1380                          $len = $space_left;
1381                          if (substr($word, $len - 1, 1) == "=")
1382                            $len--;
1383                          elseif (substr($word, $len - 2, 1) == "=")
1384                            $len -= 2;
1385                          $part = substr($word, 0, $len);
1386                          $word = substr($word, $len);
1387                          $buf .= " " . $part;
1388                          $message .= $buf . sprintf("=%s", $this->LE);
1389                      }
1390                      else
1391                      {
1392                          $message .= $buf . $soft_break;
1393                      }
1394                      $buf = "";
1395                  }
1396                  while (strlen($word) > 0)
1397                  {
1398                      $len = $length;
1399                      if (substr($word, $len - 1, 1) == "=")
1400                          $len--;
1401                      elseif (substr($word, $len - 2, 1) == "=")
1402                          $len -= 2;
1403                      $part = substr($word, 0, $len);
1404                      $word = substr($word, $len);
1405  
1406                      if (strlen($word) > 0)
1407                          $message .= $part . sprintf("=%s", $this->LE);
1408                      else
1409                          $buf = $part;
1410                  }
1411                }
1412                else
1413                {
1414                  $buf_o = $buf;
1415                  $buf .= ($e == 0) ? $word : (" " . $word); 
1416  
1417                  if (strlen($buf) > $length and $buf_o != "")
1418                  {
1419                      $message .= $buf_o . $soft_break;
1420                      $buf = $word;
1421                  }
1422                }
1423            }
1424            $message .= $buf . $this->LE;
1425          }
1426  
1427          return $message;
1428      }
1429  
1430  }


Généré le : Sun Feb 25 17:20:01 2007 par Balluche grâce à PHPXref 0.7