Back to index

d-push  2.0
vcarddir.php
Go to the documentation of this file.
00001 <?php
00002 /***********************************************
00003 * File      :   vcarddir.php
00004 * Project   :   Z-Push
00005 * Descr     :   This backend is for vcard directories.
00006 *
00007 * Created   :   01.10.2007
00008 *
00009 * Copyright 2007 - 2011 Zarafa Deutschland GmbH
00010 *
00011 * This program is free software: you can redistribute it and/or modify
00012 * it under the terms of the GNU Affero General Public License, version 3,
00013 * as published by the Free Software Foundation with the following additional
00014 * term according to sec. 7:
00015 *
00016 * According to sec. 7 of the GNU Affero General Public License, version 3,
00017 * the terms of the AGPL are supplemented with the following terms:
00018 *
00019 * "Zarafa" is a registered trademark of Zarafa B.V.
00020 * "Z-Push" is a registered trademark of Zarafa Deutschland GmbH
00021 * The licensing of the Program under the AGPL does not imply a trademark license.
00022 * Therefore any rights, title and interest in our trademarks remain entirely with us.
00023 *
00024 * However, if you propagate an unmodified version of the Program you are
00025 * allowed to use the term "Z-Push" to indicate that you distribute the Program.
00026 * Furthermore you may use our trademarks where it is necessary to indicate
00027 * the intended purpose of a product or service provided you use it in accordance
00028 * with honest practices in industrial or commercial matters.
00029 * If you want to propagate modified versions of the Program under the name "Z-Push",
00030 * you may only do so if you have a written permission by Zarafa Deutschland GmbH
00031 * (to acquire a permission please contact Zarafa at trademark@zarafa.com).
00032 *
00033 * This program is distributed in the hope that it will be useful,
00034 * but WITHOUT ANY WARRANTY; without even the implied warranty of
00035 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
00036 * GNU Affero General Public License for more details.
00037 *
00038 * You should have received a copy of the GNU Affero General Public License
00039 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
00040 *
00041 * Consult LICENSE file for details
00042 ************************************************/
00043 include_once('lib/default/diffbackend/diffbackend.php');
00044 
00045 class BackendVCardDir extends BackendDiff {
00063     public function Logon($username, $domain, $password) {
00064         return true;
00065     }
00066 
00073     public function Logoff() {
00074         return true;
00075     }
00076 
00087     public function SendMail($sm) {
00088         return false;
00089     }
00090 
00097     public function GetWasteBasket() {
00098         return false;
00099     }
00100 
00111     public function GetAttachmentData($attname) {
00112         return false;
00113     }
00114 
00126     public function GetFolderList() {
00127         ZLog::Write(LOGLEVEL_DEBUG, 'VCDir::GetFolderList()');
00128         $contacts = array();
00129         $folder = $this->StatFolder("root");
00130         $contacts[] = $folder;
00131 
00132         return $contacts;
00133     }
00134 
00143     public function GetFolder($id) {
00144         ZLog::Write(LOGLEVEL_DEBUG, 'VCDir::GetFolder('.$id.')');
00145         if($id == "root") {
00146             $folder = new SyncFolder();
00147             $folder->serverid = $id;
00148             $folder->parentid = "0";
00149             $folder->displayname = "Contacts";
00150             $folder->type = SYNC_FOLDER_TYPE_CONTACT;
00151 
00152             return $folder;
00153         } else return false;
00154     }
00155 
00164     public function StatFolder($id) {
00165         ZLog::Write(LOGLEVEL_DEBUG, 'VCDir::StatFolder('.$id.')');
00166         $folder = $this->GetFolder($id);
00167 
00168         $stat = array();
00169         $stat["id"] = $id;
00170         $stat["parent"] = $folder->parentid;
00171         $stat["mod"] = $folder->displayname;
00172 
00173         return $stat;
00174     }
00175 
00190     public function ChangeFolder($folderid, $oldid, $displayname, $type){
00191         return false;
00192     }
00193 
00205     public function DeleteFolder($id, $parentid){
00206         return false;
00207     }
00208 
00218     public function GetMessageList($folderid, $cutoffdate) {
00219         ZLog::Write(LOGLEVEL_DEBUG, 'VCDir::GetMessageList('.$folderid.')');
00220         $messages = array();
00221 
00222         $dir = opendir($this->getPath());
00223         if(!$dir)
00224             return false;
00225 
00226         while($entry = readdir($dir)) {
00227             if(is_dir($this->getPath() .'/'.$entry))
00228                 continue;
00229 
00230             $message = array();
00231             $message["id"] = $entry;
00232             $stat = stat($this->getPath() .'/'.$entry);
00233             $message["mod"] = $stat["mtime"];
00234             $message["flags"] = 1; // always 'read'
00235 
00236             $messages[] = $message;
00237         }
00238 
00239         return $messages;
00240     }
00241 
00252     public function GetMessage($folderid, $id, $contentparameters) {
00253         ZLog::Write(LOGLEVEL_DEBUG, 'VCDir::GetMessage('.$folderid.', '.$id.', ..)');
00254         if($folderid != "root")
00255             return;
00256 
00257         $types = array ('dom' => 'type', 'intl' => 'type', 'postal' => 'type', 'parcel' => 'type', 'home' => 'type', 'work' => 'type',
00258             'pref' => 'type', 'voice' => 'type', 'fax' => 'type', 'msg' => 'type', 'cell' => 'type', 'pager' => 'type',
00259             'bbs' => 'type', 'modem' => 'type', 'car' => 'type', 'isdn' => 'type', 'video' => 'type',
00260             'aol' => 'type', 'applelink' => 'type', 'attmail' => 'type', 'cis' => 'type', 'eworld' => 'type',
00261             'internet' => 'type', 'ibmmail' => 'type', 'mcimail' => 'type',
00262             'powershare' => 'type', 'prodigy' => 'type', 'tlx' => 'type', 'x400' => 'type',
00263             'gif' => 'type', 'cgm' => 'type', 'wmf' => 'type', 'bmp' => 'type', 'met' => 'type', 'pmb' => 'type', 'dib' => 'type',
00264             'pict' => 'type', 'tiff' => 'type', 'pdf' => 'type', 'ps' => 'type', 'jpeg' => 'type', 'qtime' => 'type',
00265             'mpeg' => 'type', 'mpeg2' => 'type', 'avi' => 'type',
00266             'wave' => 'type', 'aiff' => 'type', 'pcm' => 'type',
00267             'x509' => 'type', 'pgp' => 'type', 'text' => 'value', 'inline' => 'value', 'url' => 'value', 'cid' => 'value', 'content-id' => 'value',
00268             '7bit' => 'encoding', '8bit' => 'encoding', 'quoted-printable' => 'encoding', 'base64' => 'encoding',
00269         );
00270 
00271 
00272         // Parse the vcard
00273         $message = new SyncContact();
00274 
00275         $data = file_get_contents($this->getPath() . "/" . $id);
00276         $data = str_replace("\x00", '', $data);
00277         $data = str_replace("\r\n", "\n", $data);
00278         $data = str_replace("\r", "\n", $data);
00279         $data = preg_replace('/(\n)([ \t])/i', '', $data);
00280 
00281         $lines = explode("\n", $data);
00282 
00283         $vcard = array();
00284         foreach($lines as $line) {
00285             if (trim($line) == '')
00286                 continue;
00287             $pos = strpos($line, ':');
00288             if ($pos === false)
00289                 continue;
00290 
00291             $field = trim(substr($line, 0, $pos));
00292             $value = trim(substr($line, $pos+1));
00293 
00294             $fieldparts = preg_split('/(?<!\\\\)(\;)/i', $field, -1, PREG_SPLIT_NO_EMPTY);
00295 
00296             $type = strtolower(array_shift($fieldparts));
00297 
00298             $fieldvalue = array();
00299 
00300             foreach ($fieldparts as $fieldpart) {
00301                 if(preg_match('/([^=]+)=(.+)/', $fieldpart, $matches)){
00302                     if(!in_array(strtolower($matches[1]),array('value','type','encoding','language')))
00303                         continue;
00304                     if(isset($fieldvalue[strtolower($matches[1])]) && is_array($fieldvalue[strtolower($matches[1])])){
00305                         $fieldvalue[strtolower($matches[1])] = array_merge($fieldvalue[strtolower($matches[1])], preg_split('/(?<!\\\\)(\,)/i', $matches[2], -1, PREG_SPLIT_NO_EMPTY));
00306                     }else{
00307                         $fieldvalue[strtolower($matches[1])] = preg_split('/(?<!\\\\)(\,)/i', $matches[2], -1, PREG_SPLIT_NO_EMPTY);
00308                     }
00309                 }else{
00310                     if(!isset($types[strtolower($fieldpart)]))
00311                         continue;
00312                     $fieldvalue[$types[strtolower($fieldpart)]][] = $fieldpart;
00313                 }
00314             }
00315             //
00316             switch ($type) {
00317                 case 'categories':
00318                     //case 'nickname':
00319                     $val = preg_split('/(?<!\\\\)(\,)/i', $value);
00320                     $val = array_map("w2ui", $val);
00321                     break;
00322                 default:
00323                     $val = preg_split('/(?<!\\\\)(\;)/i', $value);
00324                     break;
00325             }
00326             if(isset($fieldvalue['encoding'][0])){
00327                 switch(strtolower($fieldvalue['encoding'][0])){
00328                     case 'q':
00329                     case 'quoted-printable':
00330                         foreach($val as $i => $v){
00331                             $val[$i] = quoted_printable_decode($v);
00332                         }
00333                         break;
00334                     case 'b':
00335                     case 'base64':
00336                         foreach($val as $i => $v){
00337                             $val[$i] = base64_decode($v);
00338                         }
00339                         break;
00340                 }
00341             }else{
00342                 foreach($val as $i => $v){
00343                     $val[$i] = $this->unescape($v);
00344                 }
00345             }
00346             $fieldvalue['val'] = $val;
00347             $vcard[$type][] = $fieldvalue;
00348         }
00349 
00350         if(isset($vcard['email'][0]['val'][0]))
00351             $message->email1address = $vcard['email'][0]['val'][0];
00352         if(isset($vcard['email'][1]['val'][0]))
00353             $message->email2address = $vcard['email'][1]['val'][0];
00354         if(isset($vcard['email'][2]['val'][0]))
00355             $message->email3address = $vcard['email'][2]['val'][0];
00356 
00357         if(isset($vcard['tel'])){
00358             foreach($vcard['tel'] as $tel) {
00359                 if(!isset($tel['type'])){
00360                     $tel['type'] = array();
00361                 }
00362                 if(in_array('car', $tel['type'])){
00363                     $message->carphonenumber = $tel['val'][0];
00364                 }elseif(in_array('pager', $tel['type'])){
00365                     $message->pagernumber = $tel['val'][0];
00366                 }elseif(in_array('cell', $tel['type'])){
00367                     $message->mobilephonenumber = $tel['val'][0];
00368                 }elseif(in_array('home', $tel['type'])){
00369                     if(in_array('fax', $tel['type'])){
00370                         $message->homefaxnumber = $tel['val'][0];
00371                     }elseif(empty($message->homephonenumber)){
00372                         $message->homephonenumber = $tel['val'][0];
00373                     }else{
00374                         $message->home2phonenumber = $tel['val'][0];
00375                     }
00376                 }elseif(in_array('work', $tel['type'])){
00377                     if(in_array('fax', $tel['type'])){
00378                         $message->businessfaxnumber = $tel['val'][0];
00379                     }elseif(empty($message->businessphonenumber)){
00380                         $message->businessphonenumber = $tel['val'][0];
00381                     }else{
00382                         $message->business2phonenumber = $tel['val'][0];
00383                     }
00384                 }elseif(empty($message->homephonenumber)){
00385                     $message->homephonenumber = $tel['val'][0];
00386                 }elseif(empty($message->home2phonenumber)){
00387                     $message->home2phonenumber = $tel['val'][0];
00388                 }else{
00389                     $message->radiophonenumber = $tel['val'][0];
00390                 }
00391             }
00392         }
00393         //;;street;city;state;postalcode;country
00394         if(isset($vcard['adr'])){
00395             foreach($vcard['adr'] as $adr) {
00396                 if(empty($adr['type'])){
00397                     $a = 'other';
00398                 }elseif(in_array('home', $adr['type'])){
00399                     $a = 'home';
00400                 }elseif(in_array('work', $adr['type'])){
00401                     $a = 'business';
00402                 }else{
00403                     $a = 'other';
00404                 }
00405                 if(!empty($adr['val'][2])){
00406                     $b=$a.'street';
00407                     $message->$b = w2ui($adr['val'][2]);
00408                 }
00409                 if(!empty($adr['val'][3])){
00410                     $b=$a.'city';
00411                     $message->$b = w2ui($adr['val'][3]);
00412                 }
00413                 if(!empty($adr['val'][4])){
00414                     $b=$a.'state';
00415                     $message->$b = w2ui($adr['val'][4]);
00416                 }
00417                 if(!empty($adr['val'][5])){
00418                     $b=$a.'postalcode';
00419                     $message->$b = w2ui($adr['val'][5]);
00420                 }
00421                 if(!empty($adr['val'][6])){
00422                     $b=$a.'country';
00423                     $message->$b = w2ui($adr['val'][6]);
00424                 }
00425             }
00426         }
00427 
00428         if(!empty($vcard['fn'][0]['val'][0]))
00429             $message->fileas = w2ui($vcard['fn'][0]['val'][0]);
00430         if(!empty($vcard['n'][0]['val'][0]))
00431             $message->lastname = w2ui($vcard['n'][0]['val'][0]);
00432         if(!empty($vcard['n'][0]['val'][1]))
00433             $message->firstname = w2ui($vcard['n'][0]['val'][1]);
00434         if(!empty($vcard['n'][0]['val'][2]))
00435             $message->middlename = w2ui($vcard['n'][0]['val'][2]);
00436         if(!empty($vcard['n'][0]['val'][3]))
00437             $message->title = w2ui($vcard['n'][0]['val'][3]);
00438         if(!empty($vcard['n'][0]['val'][4]))
00439             $message->suffix = w2ui($vcard['n'][0]['val'][4]);
00440         if(!empty($vcard['bday'][0]['val'][0])){
00441             $tz = date_default_timezone_get();
00442             date_default_timezone_set('UTC');
00443             $message->birthday = strtotime($vcard['bday'][0]['val'][0]);
00444             date_default_timezone_set($tz);
00445         }
00446         if(!empty($vcard['org'][0]['val'][0]))
00447             $message->companyname = w2ui($vcard['org'][0]['val'][0]);
00448         if(!empty($vcard['note'][0]['val'][0])){
00449             $message->body = w2ui($vcard['note'][0]['val'][0]);
00450             $message->bodysize = strlen($vcard['note'][0]['val'][0]);
00451             $message->bodytruncated = 0;
00452         }
00453         if(!empty($vcard['role'][0]['val'][0]))
00454             $message->jobtitle = w2ui($vcard['role'][0]['val'][0]);//$vcard['title'][0]['val'][0]
00455         if(!empty($vcard['url'][0]['val'][0]))
00456             $message->webpage = w2ui($vcard['url'][0]['val'][0]);
00457         if(!empty($vcard['categories'][0]['val']))
00458             $message->categories = $vcard['categories'][0]['val'];
00459 
00460         if(!empty($vcard['photo'][0]['val'][0]))
00461             $message->picture = base64_encode($vcard['photo'][0]['val'][0]);
00462 
00463         return $message;
00464     }
00465 
00475     public function StatMessage($folderid, $id) {
00476         ZLog::Write(LOGLEVEL_DEBUG, 'VCDir::StatMessage('.$folderid.', '.$id.')');
00477         if($folderid != "root")
00478             return false;
00479 
00480         $stat = stat($this->getPath() . "/" . $id);
00481 
00482         $message = array();
00483         $message["mod"] = $stat["mtime"];
00484         $message["id"] = $id;
00485         $message["flags"] = 1;
00486 
00487         return $message;
00488     }
00489 
00502     public function ChangeMessage($folderid, $id, $message) {
00503         ZLog::Write(LOGLEVEL_DEBUG, 'VCDir::ChangeMessage('.$folderid.', '.$id.', ..)');
00504         $mapping = array(
00505             'fileas' => 'FN',
00506             'lastname;firstname;middlename;title;suffix' => 'N',
00507             'email1address' => 'EMAIL;INTERNET',
00508             'email2address' => 'EMAIL;INTERNET',
00509             'email3address' => 'EMAIL;INTERNET',
00510             'businessphonenumber' => 'TEL;WORK',
00511             'business2phonenumber' => 'TEL;WORK',
00512             'businessfaxnumber' => 'TEL;WORK;FAX',
00513             'homephonenumber' => 'TEL;HOME',
00514             'home2phonenumber' => 'TEL;HOME',
00515             'homefaxnumber' => 'TEL;HOME;FAX',
00516             'mobilephonenumber' => 'TEL;CELL',
00517             'carphonenumber' => 'TEL;CAR',
00518             'pagernumber' => 'TEL;PAGER',
00519             ';;businessstreet;businesscity;businessstate;businesspostalcode;businesscountry' => 'ADR;WORK',
00520             ';;homestreet;homecity;homestate;homepostalcode;homecountry' => 'ADR;HOME',
00521             ';;otherstreet;othercity;otherstate;otherpostalcode;othercountry' => 'ADR',
00522             'companyname' => 'ORG',
00523             'body' => 'NOTE',
00524             'jobtitle' => 'ROLE',
00525             'webpage' => 'URL',
00526         );
00527         $data = "BEGIN:VCARD\nVERSION:2.1\nPRODID:Z-Push\n";
00528         foreach($mapping as $k => $v){
00529             $val = '';
00530             $ks = explode(';', $k);
00531             foreach($ks as $i){
00532                 if(!empty($message->$i))
00533                     $val .= $this->escape($message->$i);
00534                 $val.=';';
00535             }
00536             if(empty($val))
00537                 continue;
00538             $val = substr($val,0,-1);
00539             if(strlen($val)>50){
00540                 $data .= $v.":\n\t".substr(chunk_split($val, 50, "\n\t"), 0, -1);
00541             }else{
00542                 $data .= $v.':'.$val."\n";
00543             }
00544         }
00545         if(!empty($message->categories))
00546             $data .= 'CATEGORIES:'.implode(',', $this->escape($message->categories))."\n";
00547         if(!empty($message->picture))
00548             $data .= 'PHOTO;ENCODING=BASE64;TYPE=JPEG:'."\n\t".substr(chunk_split($message->picture, 50, "\n\t"), 0, -1);
00549         if(isset($message->birthday))
00550             $data .= 'BDAY:'.date('Y-m-d', $message->birthday)."\n";
00551         $data .= "END:VCARD";
00552 
00553 // not supported: anniversary, assistantname, assistnamephonenumber, children, department, officelocation, radiophonenumber, spouse, rtf
00554 
00555         if(!$id){
00556             if(!empty($message->fileas)){
00557                 $name = u2wi($message->fileas);
00558             }elseif(!empty($message->lastname)){
00559                 $name = $name = u2wi($message->lastname);
00560             }elseif(!empty($message->firstname)){
00561                 $name = $name = u2wi($message->firstname);
00562             }elseif(!empty($message->companyname)){
00563                 $name = $name = u2wi($message->companyname);
00564             }else{
00565                 $name = 'unknown';
00566             }
00567             $name = preg_replace('/[^a-z0-9 _-]/i', '', $name);
00568             $id = $name.'.vcf';
00569             $i = 0;
00570             while(file_exists($this->getPath().'/'.$id)){
00571                 $i++;
00572                 $id = $name.$i.'.vcf';
00573             }
00574         }
00575         file_put_contents($this->getPath().'/'.$id, $data);
00576         return $this->StatMessage($folderid, $id);
00577     }
00578 
00590     public function SetReadFlag($folderid, $id, $flags) {
00591         return false;
00592     }
00593 
00604     public function DeleteMessage($folderid, $id) {
00605         return unlink($this->getPath() . '/' . $id);
00606     }
00607 
00620     public function MoveMessage($folderid, $id, $newfolderid) {
00621         return false;
00622     }
00623 
00624 
00635     private function getPath() {
00636         return str_replace('%u', $this->store, VCARDDIR_DIR);
00637     }
00638 
00647     function escape($data){
00648         if (is_array($data)) {
00649             foreach ($data as $key => $val) {
00650                 $data[$key] = $this->escape($val);
00651             }
00652             return $data;
00653         }
00654         $data = str_replace("\r\n", "\n", $data);
00655         $data = str_replace("\r", "\n", $data);
00656         $data = str_replace(array('\\', ';', ',', "\n"), array('\\\\', '\\;', '\\,', '\\n'), $data);
00657         return u2wi($data);
00658     }
00659 
00668     function unescape($data){
00669         $data = str_replace(array('\\\\', '\\;', '\\,', '\\n','\\N'),array('\\', ';', ',', "\n", "\n"),$data);
00670         return $data;
00671     }
00672 };
00673 ?>