Back to index

d-push  2.0
icalparser.php
Go to the documentation of this file.
00001 <?php
00002 /***********************************************
00003 * File      :   z_ical.php
00004 * Project   :   Z-Push
00005 * Descr     :   This is a very basic iCalendar parser
00006 *               used to process incoming meeting requests
00007 *               and responses.
00008 *
00009 * Created   :   01.12.2008
00010 *
00011 * Copyright 2007 - 2011 Zarafa Deutschland GmbH
00012 *
00013 * This program is free software: you can redistribute it and/or modify
00014 * it under the terms of the GNU Affero General Public License, version 3,
00015 * as published by the Free Software Foundation with the following additional
00016 * term according to sec. 7:
00017 *
00018 * According to sec. 7 of the GNU Affero General Public License, version 3,
00019 * the terms of the AGPL are supplemented with the following terms:
00020 *
00021 * "Zarafa" is a registered trademark of Zarafa B.V.
00022 * "Z-Push" is a registered trademark of Zarafa Deutschland GmbH
00023 * The licensing of the Program under the AGPL does not imply a trademark license.
00024 * Therefore any rights, title and interest in our trademarks remain entirely with us.
00025 *
00026 * However, if you propagate an unmodified version of the Program you are
00027 * allowed to use the term "Z-Push" to indicate that you distribute the Program.
00028 * Furthermore you may use our trademarks where it is necessary to indicate
00029 * the intended purpose of a product or service provided you use it in accordance
00030 * with honest practices in industrial or commercial matters.
00031 * If you want to propagate modified versions of the Program under the name "Z-Push",
00032 * you may only do so if you have a written permission by Zarafa Deutschland GmbH
00033 * (to acquire a permission please contact Zarafa at trademark@zarafa.com).
00034 *
00035 * This program is distributed in the hope that it will be useful,
00036 * but WITHOUT ANY WARRANTY; without even the implied warranty of
00037 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
00038 * GNU Affero General Public License for more details.
00039 *
00040 * You should have received a copy of the GNU Affero General Public License
00041 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
00042 *
00043 * Consult LICENSE file for details
00044 ************************************************/
00045 
00046 class ICalParser{
00047     private $props;
00048 
00057     public function ICalParser(&$store, &$props){
00058          $this->props = $props;
00059     }
00060 
00069     public function ExtractProps($ical, &$mapiprops) {
00070         //mapping between partstat in ical and MAPI Meeting Response classes as well as icons
00071         $aClassMap = array(
00072             "ACCEPTED"          => array("class" => "IPM.Schedule.Meeting.Resp.Pos", "icon" => 0x405),
00073             "DECLINED"          => array("class" => "IPM.Schedule.Meeting.Resp.Neg", "icon" => 0x406),
00074             "TENTATIVE"         => array("class" => "IPM.Schedule.Meeting.Resp.Tent", "icon" => 0x407),
00075             "NEEDS-ACTION"      => array("class" => "IPM.Schedule.Meeting.Request", "icon" => 0x404), //iphone
00076             "REQ-PARTICIPANT"   => array("class" => "IPM.Schedule.Meeting.Request", "icon" => 0x404), //nokia
00077         );
00078 
00079         $aical = preg_split("/[\n]/", $ical);
00080         $elemcount = count($aical);
00081         $i=0;
00082         $nextline = $aical[0];
00083 
00084         //last element is empty
00085         while ($i < $elemcount - 1) {
00086             $line = $nextline;
00087             $nextline = $aical[$i+1];
00088 
00089             //if a line starts with a space or a tab it belongs to the previous line
00090             while (strlen($nextline) > 0 && ($nextline{0} == " " || $nextline{0} == "\t")) {
00091                 $line = rtrim($line) . substr($nextline, 1);
00092                 $nextline = $aical[++$i + 1];
00093             }
00094             $line = rtrim($line);
00095 
00096             switch (strtoupper($line)) {
00097                 case "BEGIN:VCALENDAR":
00098                 case "BEGIN:VEVENT":
00099                 case "END:VEVENT":
00100                 case "END:VCALENDAR":
00101                     break;
00102                 default:
00103                     unset ($field, $data, $prop_pos, $property);
00104                     if (preg_match ("/([^:]+):(.*)/", $line, $line)){
00105                         $field = $line[1];
00106                         $data = $line[2];
00107                         $property = $field;
00108                         $prop_pos = strpos($property,';');
00109                         if ($prop_pos !== false) $property = substr($property, 0, $prop_pos);
00110                         $property = strtoupper($property);
00111 
00112                         switch ($property) {
00113                             case 'DTSTART':
00114                                 $data = $this->getTimestampFromStreamerDate($data);
00115                                 $mapiprops[$this->props["starttime"]] = $mapiprops[$this->props["commonstart"]] = $mapiprops[$this->props["clipstart"]] = $mapiprops[PR_START_DATE] = $data;
00116                                 break;
00117 
00118                             case 'DTEND':
00119                                 $data = $this->getTimestampFromStreamerDate($data);
00120                                 $mapiprops[$this->props["endtime"]] = $mapiprops[$this->props["commonend"]] = $mapiprops[$this->props["recurrenceend"]] = $mapiprops[PR_END_DATE] = $data;
00121                                 break;
00122 
00123                             case 'UID':
00124                                 $mapiprops[$this->props["goidtag"]] = $mapiprops[$this->props["goid2tag"]] = Utils::GetOLUidFromICalUid($data);
00125                                 break;
00126 
00127                             case 'ATTENDEE':
00128                                 $fields = explode(";", $field);
00129                                 foreach ($fields as $field) {
00130                                     $prop_pos     = strpos($field, '=');
00131                                     if ($prop_pos !== false) {
00132                                         switch (substr($field, 0, $prop_pos)) {
00133                                             case 'PARTSTAT'    : $partstat = substr($field, $prop_pos+1); break;
00134                                             case 'CN'        : $cn = substr($field, $prop_pos+1); break;
00135                                             case 'ROLE'        : $role = substr($field, $prop_pos+1); break;
00136                                             case 'RSVP'        : $rsvp = substr($field, $prop_pos+1); break;
00137                                         }
00138                                     }
00139                                 }
00140                                 if (isset($partstat) && isset($aClassMap[$partstat]) &&
00141 
00142                                    (!isset($mapiprops[PR_MESSAGE_CLASS]) || $mapiprops[PR_MESSAGE_CLASS] == "IPM.Schedule.Meeting.Request")) {
00143                                     $mapiprops[PR_MESSAGE_CLASS] = $aClassMap[$partstat]['class'];
00144                                     $mapiprops[PR_ICON_INDEX] = $aClassMap[$partstat]['icon'];
00145                                 }
00146                                 // START ADDED dw2412 to support meeting requests on HTC Android Mail App
00147                                 elseif (isset($role) && isset($aClassMap[$role]) &&
00148                                    (!isset($mapiprops[PR_MESSAGE_CLASS]) || $mapiprops[PR_MESSAGE_CLASS] == "IPM.Schedule.Meeting.Request")) {
00149                                     $mapiprops[PR_MESSAGE_CLASS] = $aClassMap[$role]['class'];
00150                                     $mapiprops[PR_ICON_INDEX] = $aClassMap[$role]['icon'];
00151                                 }
00152                                 // END ADDED dw2412 to support meeting requests on HTC Android Mail App
00153                                 if (!isset($cn)) $cn = "";
00154                                 $data         = str_replace ("MAILTO:", "", $data);
00155                                 $attendee[] = array ('name' => stripslashes($cn), 'email' => stripslashes($data));
00156                                 break;
00157 
00158                             case 'ORGANIZER':
00159                                 $field          = str_replace("ORGANIZER;CN=", "", $field);
00160                                 $data          = str_replace ("MAILTO:", "", $data);
00161                                 $organizer[] = array ('name' => stripslashes($field), 'email' => stripslashes($data));
00162                                 break;
00163 
00164                             case 'LOCATION':
00165                                 $data = str_replace("\\n", "<br />", $data);
00166                                 $data = str_replace("\\t", "&nbsp;", $data);
00167                                 $data = str_replace("\\r", "<br />", $data);
00168                                 $data = stripslashes($data);
00169                                 $mapiprops[$this->props["tneflocation"]] = $mapiprops[$this->props["location"]] = $data;
00170                                 break;
00171                         }
00172                     }
00173                     break;
00174             }
00175             $i++;
00176 
00177         }
00178         $mapiprops[$this->props["usetnef"]] = true;
00179     }
00180 
00189     private function getTimestampFromStreamerDate ($data) {
00190         $data = str_replace('Z', '', $data);
00191         $data = str_replace('T', '', $data);
00192 
00193         preg_match ('/([0-9]{4})([0-9]{2})([0-9]{2})([0-9]{0,2})([0-9]{0,2})([0-9]{0,2})/', $data, $regs);
00194         if ($regs[1] < 1970) {
00195             $regs[1] = '1971';
00196         }
00197         return gmmktime($regs[4], $regs[5], $regs[6], $regs[2], $regs[3], $regs[1]);
00198     }
00199 }
00200 
00201 ?>