Terrano Posté(e) le 1 octobre 2015 Partager Posté(e) le 1 octobre 2015 (modifié) Si vous avez suivi mes précédents tutos pour CardDav, notamment celui-ci : Vous avez tous vos contacts de vos téléphones mobiles dans votre messagerie Mail. C'est déjà bien mais le must serait que cela soit utilisé encore plus. Le but de ce tutorial est triple : Ajouter une vue et un export de vos contacts pour synchroniser avec d'autres outils Ajouter vos contacts sur le répertoire téléphonique de vos téléphones IP A noter que j'ai testé et validé le fonctionnement du système en utilisant la fonctionnalité de Provisioning de mes téléphones IP Alcatel à savoir : 2 Alcatel Temporis IP600 (POE, SIP, Filaire) 1 Alcatel IP 1020 (POE, SIP, DECT) Nous allons procéder en plusieurs étapes. Export de l'annuaire CardDav Se connecter en ssh au Synology. Taper les commandes suivantes : mkdir /volume1/scripts mkdir /volume1/scripts/CardDav mkdir /volume1/web/tel mkdir /volume1/web/carddav cd /volume1/scripts/CardDav vi carddav.sh Nous allons mettre en place un script BASH pour exporter le contenu d'un annuaire, voici le script. Tapez i et insérez le code suivant : #!/bin/sh DIR=/volume1/scripts/CardDav HTMLXML="https://www.mondomaine.fr/carddav/carddav.php?action=EXTRACT&file=book&format=XML&view=FILE&option=ATR" HTMLCSV="https://www.mondomaine.fr/carddav/carddav.php?action=EXTRACT&file=book&format=CSV&view=FILE" ALC=/volume1/web/tel/contactData1.xml AST=/volume1/web/carddav/book.csv job () { ADDRESSBOOK=$SERVER"/addressbooks/users/"$USER"/addressbook/" rm $FILE"vcf.txt" rm $FILE".txt" curl -X PROPFIND -u $USER:$PASSWORD -H "Content-Type: text/xml" -H "Depth: 1" --data "<propfind xmlns='DAV:'><prop><address-data xmlns='urn:ietf:params:xml:ns:carddav'/></prop></propfind>" "$ADDRESSBOOK" -k >> $FILE"vcf.txt" while IFS='' read -r line || [[ -n "$line" ]]; do case "$line" in *".vcf"*) url=${line%</href>*} url=${url#*<href>} curl -u $USER:$PASSWORD -H "Content-Type: text/xml" "$SERVER$url" -k >> $FILE".txt" ;; *) ;; esac done < $FILE"vcf.txt" wget --no-check-certificate $HTMLXML -O $ALC wget --no-check-certificate $HTMLCSV -O $AST } while getopts "a:u:p:f:s:" opt; do case $opt in a) echo "-a was triggered, Parameter: $OPTARG" >&2 ACTION=$OPTARG ;; u) echo "-u was triggered, Parameter: $OPTARG" >&2 USER=$OPTARG ;; p) echo "-p was triggered, Parameter: $OPTARG" >&2 PASSWORD=$OPTARG ;; f) echo "-f was triggered, Parameter: $OPTARG" >&2 FILE=$OPTARG ;; s) echo "-s was triggered, Parameter: $OPTARG" >&2 SERVER=$OPTARG ;; \?) echo "Invalid option: -$OPTARG" >&2 exit 1 ;; :) echo "Option -$OPTARG requires an argument." >&2 exit 1 ;; esac done cd $DIR case "$ACTION" in ("JOB") echo $(job) ;; (*) exit 1 ;; esac Appuyez sur Echappement, puis :wq pour sauvegarder le fichier. Rendre le fichier exécutable avec : chmod 755 carddav.sh Les variables dans le script : DIR : Dossier du script HTML : Lien HTTP ou HTTPS vers la vue et export PHP (installation dans la deuxième étape) ALC : Dossier et nom du fichier pour le provisioning des contacts pour les téléphones Alcatel Les paramètres d'exécution du script : -a JOB : Exécution du job du script -u user : Identifiant de l'utilisateur CardDav (utilisateur du Synology) -p password : Mot de passe Synology pour l'utilisateur précédent -f file : Libellé du fichier généré (au cas où on met en place l'export de plusieurs annuaires CardDav -s https://localhost:8443 : Lien HTTP du serveur CardDav (hébergé sur le Synology) Mise en place des vues et exports PHP La première chose à faire, est d'autoriser PHP à accèder à certains dossiers. Sous l'interface DSM, aller dans Panneau de Configuration,Services Web, Paramètres PHP et ajouter les éléments suivant au début de la variable PHP open_basedir : /volume1/web:/volume1/scripts: Reste à ajouter les scripts PHP suivant dans le dossier /volume1/web/carddav : class.php : <?php $carddav_dir = "/volume1/scripts/CardDav/"; $carddav_sh = $carddav_dir."carddav.sh"; $ssh2_ip = "ipdusyno"; $ssh2_port = "portssh"; $ssh2_password = "passwordssh"; $ssh2_account = "comptessh"; $carddavserver = "https://localhost:8443"; include_once(dirname(__FILE__) . "/vcard.php"); function strWithoutAccent($string){ $string = htmlentities($string, ENT_NOQUOTES, 'utf-8'); $string = preg_replace('#&([A-za-z])(?:uml|circ|tilde|acute|grave|cedil|ring);#', '\1', $string); $string = preg_replace('#&([A-za-z]{2})(?:lig);#', '\1', $string); $string = preg_replace('#&[^;]+;#', '', $string); return $string; } function isJSON($string){ return is_string($string) && is_object(json_decode($string)) ? true : false; } function xml_to_array($xml,$main_heading = '') { $deXml = simplexml_load_string($xml); $deJson = json_encode($deXml); $xml_array = json_decode($deJson,TRUE); if (! empty($main_heading)) { $returned = $xml_array[$main_heading]; return $returned; } else { return $xml_array; } } function arguments ( $args ){ array_shift( $args ); $endofoptions = false; $ret = array ( 'commands' => array(), 'options' => array(), 'flags' => array(), 'arguments' => array(), ); while ( $arg = array_shift($args) ) { // if we have reached end of options, //we cast all remaining argvs as arguments if ($endofoptions) { $ret['arguments'][] = $arg; continue; } // Is it a command? (prefixed with --) if ( substr( $arg, 0, 2 ) === '--' ) { // is it the end of options flag? if (!isset ($arg[3])) { $endofoptions = true;; // end of options; continue; } $value = ""; $com = substr( $arg, 2 ); // is it the syntax '--option=argument'? if (strpos($com,'=')) list($com,$value) = split("=",$com,2); // is the option not followed by another option but by arguments elseif (strpos($args[0],'-') !== 0) { while (strpos($args[0],'-') !== 0) $value .= array_shift($args).' '; $value = rtrim($value,' '); } $ret['options'][$com] = !empty($value) ? $value : true; continue; } // Is it a flag or a serial of flags? (prefixed with -) if ( substr( $arg, 0, 1 ) === '-' ) { for ($i = 1; isset($arg[$i]) ; $i++) $ret['flags'][] = $arg[$i]; continue; } // finally, it is not option, nor flag, nor argument $ret['commands'][] = $arg; continue; } if (!count($ret['options']) && !count($ret['flags'])) { $ret['arguments'] = array_merge($ret['commands'], $ret['arguments']); $ret['commands'] = array(); } return $ret; } function makeXML($user, $password, $file){ $stack = array(); global $carddav_sh, $ssh2_ip, $ssh2_port, $ssh2_account, $ssh2_password, $carddavserver; $connection = ssh2_connect($ssh2_ip, $ssh2_port); if (!ssh2_auth_password($connection, $ssh2_account, $ssh2_password)) { array_push($stack, 'Echec de l\'identification...'); die(); } $stream = ssh2_exec($connection, $carddav_sh.' -a JOB -u '.$user.' -p '.$password.' -f '.$file.' -s '.$carddavserver); // Enable blocking for both streams stream_set_blocking($stream, true); while($line = fgets($stream)) { flush(); array_push($stack, $line); } // Close the streams fclose($stream); ssh2_exec($connection, 'exit'); unset($connection); } function string_to_ascii($string){ $ascii = NULL; for ($i = 0; $i < strlen($string); $i++) { $ascii = $ascii.'/'.ord($string[$i]); } return($ascii); } function print_vcard_address_book($file, $title, $style, $cat, $hide){ if ($title) { $title = stripcslashes($title); } else if ($file) { $title = $file; } else { $title = "vCard PHP - A vCard Address Book"; } echo "<html>\n<head>\n<title>$title</title>\n"; header('Content-Type: text/html; charset=utf-8'); if (!$style) { $style = "style.css"; } echo "<link href='$style' type='text/css' rel='stylesheet'>\n"; echo "</head>\n<body>\n"; echo "<h1>$title</h1>\n"; if (!$file) { exit('Required $file parameter not specified.'); } $lines = file($file); if (!$lines) { exit("Can't read the vCard file: $file"); } $cards = parse_vcards($lines); print_vcards($cards, $cat, $hide); echo "</body>\n</html>\n"; } /** * Prints a set of vCards in two columns. The $categories_to_display is a * comma delimited list of categories. */ function print_vcards(&$cards, $categories_to_display, $hide){ $all_categories = get_vcard_categories($cards); if (!$categories_to_display) { $categories_to_display = array('All'); } else if ($categories_to_display == '*') { $categories_to_display = $all_categories; } else { $categories_to_display = explode(',', $categories_to_display); } if ($hide) { $hide = explode(',', $hide); } else { $hide = array(); } echo "<p class='categories'>\nCategories: "; echo join(', ', $categories_to_display); echo "<br />\n</p>\n"; $i = 0; foreach ($cards as $card_name => $card) { if (!$card->inCategories($categories_to_display)) { continue; } if ($i == 0) { echo "<table width='100%' cellspacing='4' border='0'>\n"; echo "<tr>\n"; } echo "<td class='vcard' width='50%' valign='top'>\n"; echo "<p class='name'><strong>$card_name</strong>"; // Add the categories (if present) after the name. $property = $card->getProperty('CATEGORIES'); if ($property) { // Replace each comma by a comma and a space. $categories = $property->getComponents(','); $categories = join(', ', $categories); echo " ($categories)"; } echo "</p>\n"; print_vcard($card, $hide); echo "</td>\n"; $i = ($i + 1) % 2; if ($i == 0) { echo "</tr>\n"; echo "</table>\n"; } } if ($i != 0) { echo "<td> </td>\n"; echo "</tr>\n"; echo "</table>\n"; } } /** * Prints the vCard as HTML. */ function print_vcard($card, $hide){ $names = array('FN', 'TITLE', 'ORG', 'TEL', 'EMAIL', 'URL', 'ADR', 'BDAY', 'NOTE'); $row = 0; foreach ($names as $name) { if (in_array_case($name, $hide)) { continue; } $properties = $card->getProperties($name); if ($properties) { foreach ($properties as $property) { $show = true; $types = $property->params['TYPE']; if ($types) { foreach ($types as $type) { if (in_array_case($type, $hide)) { $show = false; break; } } } if ($show) { $class = ($row++ % 2 == 0) ? "property-even" : "property-odd"; print_vcard_property($property, $class, $hide); } } } } } /** * Prints a VCardProperty as HTML. */ function print_vcard_property($property, $class, $hide){ $name = $property->name; $value = $property->value; switch ($name) { case 'ADR': $adr = $property->getComponents(); $lines = array(); for ($i = 0; $i < 3; $i++) { if ($adr[$i]) { $lines[] = $adr[$i]; } } $city_state_zip = array(); for ($i = 3; $i < 6; $i++) { if ($adr[$i]) { $city_state_zip[] = $adr[$i]; } } if ($city_state_zip) { // Separate the city, state, and zip with spaces and add // it as the last line. $lines[] = join(" ", $city_state_zip); } // Add the country. if ($adr[6]) { $lines[] = $adr[6]; } $html = join("\n", $lines); break; case 'EMAIL': $html = "<a href='mailto:$value'>$value</a>"; break; case 'URL': $html = "<a href='$value' target='_base'>$value</a>"; break; case 'BDAY': $html = "Birthdate: $value"; break; default: $components = $property->getComponents(); $lines = array(); foreach ($components as $component) { if ($component) { $lines[] = $component; } } $html = join("\n", $lines); break; } echo "<p class='$class'>\n"; echo nl2br(stripcslashes($html)); $types = $property->params['TYPE']; if ($types) { $type = join(", ", $types); echo " (" . ucwords(strtolower($type)) . ")"; } echo "\n</p>\n"; } function get_vcard_categories(&$cards){ $unfiled = false; // set if there is at least one unfiled card $result = array(); foreach ($cards as $card_name => $card) { $properties = $card->getProperties('CATEGORIES'); if ($properties) { foreach ($properties as $property) { $categories = $property->getComponents(','); foreach ($categories as $category) { if (!in_array($category, $result)) { $result[] = $category; } } } } else { $unfiled = true; } } if ($unfiled && !in_array('Unfiled', $result)) { $result[] = 'Unfiled'; } return $result; } function parse_vcards(&$lines){ $cards = array(); $card = new VCard(); while ($card->parse($lines)) { $property = $card->getProperty('FN'); if (!$property) { return ""; } $n = $property->getComponents(); $tmp = array(); if ($n[3]) $tmp[] = $n[3]; // Mr. if ($n[1]) $tmp[] = $n[1]; // John if ($n[2]) $tmp[] = $n[2]; // Quinlan if ($n[4]) $tmp[] = $n[4]; // Esq. $ret = array(); if ($n[0]) $ret[] = $n[0]; $tmp = join(" ", $tmp); if ($tmp) $ret[] = $tmp; $key = join(", ", $ret); $cards[$key] = $card; $card = new VCard(); } ksort($cards); return $cards; } // ----- Utility Functions ----- /** * Checks if needle $str is in haystack $arr but ignores case. */ function in_array_case($str, $arr){ foreach ($arr as $s) { if (strcasecmp($str, $s) == 0) { return true; } } return false; } function convert_french_type($type){ $types = array('HOME' => 'Domicile','HOME2' => 'Domicile','WORK' => 'Travail', 'WORK2' => 'Travail', 'MOBILE' => 'Mobile', 'CELL' => 'Mobile', 'MAIN' => 'Principal', 'OTHER' => 'Autre', 'HOMEFAX' => 'Fax', 'WORKFAX' => 'Fax', 'CAR' => 'Voiture', 'PAGER' => 'Pager', 'VIDEO' => 'Video', 'ASSISTANT' => 'Assistant'); return $types[$type]; } ?> vcard.php : <?php /* * File: * vcard.php * * Project: * vCard PHP <http://vcardphp.sourceforge.net> * * Author: * Frank Hellwig <frank@hellwig.org> * * Usage: * Use the following URL to display the help text: * * http://host/path/vcard.php */ /** * The VCard class encapsulates a single vCard object by maintaining a map of * property names to one or more property values associated with that name. * A name is the unique property identifier such as N, ADR, and TEL. */ class VCard { /** * An associative array where each key is the property name and each value * is a VCardProperty array of properties which share that property name. */ var $_map; /** * Parses a vCard from one or more lines. Lines that are not property * lines, such as blank lines, are skipped. Returns false if there are * no more lines to be parsed. */ function parse(&$lines) { $this->_map = null; $property = new VCardProperty(); while ($property->parse($lines)) { if (is_null($this->_map)) { if ($property->name == 'BEGIN') { $this->_map = array(); } } else { if ($property->name == 'END') { break; } else { $this->_map[$property->name][] = $property; } } // MDH: Create new property to prevent overwriting previous one // (PHP5) $property = new VCardProperty(); } return $this->_map != null; } /** * Returns the first property mapped to the specified name or null if * there are no properties with that name. */ function getProperty($name) { return $this->_map[$name][0]; } /** * Returns the properties mapped to the specified name or null if * there are no properties with that name. */ function getProperties($name) { return $this->_map[$name]; } /** * Returns an array of categories for this card or a one-element array with * the value 'Unfiled' if no CATEGORIES property is found. */ function getCategories() { $property = $this->getProperty('CATEGORIES'); // The Mac OS X Address Book application uses the CATEGORY property // instead of the CATEGORIES property. if (!$property) { $property = $this->getProperty('CATEGORY'); } if ($property) { $result = $property->getComponents(','); } else { $result = array('Unfiled'); } $result[] = "All"; // Each card is always a member of "All" return $result; } /** * Returns true if the card belongs to at least one of the categories. */ function inCategories(&$categories) { $our_categories = $this->getCategories(); foreach ($categories as $category) { if (in_array_case($category, $our_categories)) { return true; } } return false; } } /** * The VCardProperty class encapsulates a single vCard property consisting * of a name, zero or more parameters, and a value. * * The parameters are stored as an associative array where each key is the * parameter name and each value is an array of parameter values. */ class VCardProperty { var $name; // string var $params; // params[PARAM_NAME] => value[,value...] var $value; // string /** * Parses a vCard property from one or more lines. Lines that are not * property lines, such as blank lines, are skipped. Returns false if * there are no more lines to be parsed. */ function parse(&$lines) { while (list(, $line) = each($lines)) { $line = rtrim($line); $tmp = split_quoted_string(":", $line, 2); if (count($tmp) == 2) { $this->value = $tmp[1]; $tmp = strtoupper($tmp[0]); $tmp = split_quoted_string(";", $tmp); $this->name = $tmp[0]; $this->params = array(); for ($i = 1; $i < count($tmp); $i++) { $this->_parseParam($tmp[$i]); } if ($this->params['ENCODING'][0] == 'QUOTED-PRINTABLE') { $this->_decodeQuotedPrintable($lines); } if ($this->params['CHARSET'][0] == 'UTF-8') { $this->value = utf8_decode($this->value); } return true; } } return false; } /** * Splits the value on unescaped delimiter characters. */ function getComponents($delim = ";") { $value = $this->value; // Save escaped delimiters. $value = str_replace("\\$delim", "\x00", $value); // Tag unescaped delimiters. $value = str_replace("$delim", "\x01", $value); // Restore the escaped delimiters. $value = str_replace("\x00", "$delim", $value); // Split the line on the delimiter tag. return explode("\x01", $value); } // ----- Private methods ----- /** * Parses a parameter string where the parameter string is either in the * form "name=value[,value...]" such as "TYPE=WORK,CELL" or is a * vCard 2.1 parameter value such as "WORK" in which case the parameter * name is determined from the parameter value. */ function _parseParam($param) { $tmp = split_quoted_string('=', $param, 2); if (count($tmp) == 1) { $value = $tmp[0]; $name = $this->_paramName($value); $this->params[$name][] = $value; } else { $name = $tmp[0]; $values = split_quoted_string(',', $tmp[1]); foreach ($values as $value) { $this->params[$name][] = $value; } } } /** * The vCard 2.1 specification allows parameter values without a name. * The parameter name is then determined from the unique parameter value. */ function _paramName($value) { static $types = array ( 'DOM', 'INTL', 'POSTAL', 'PARCEL','HOME', 'WORK', 'PREF', 'VOICE', 'FAX', 'MSG', 'CELL', 'PAGER', 'BBS', 'MODEM', 'CAR', 'ISDN', 'VIDEO', 'AOL', 'APPLELINK', 'ATTMAIL', 'CIS', 'EWORLD', 'INTERNET', 'IBMMAIL', 'MCIMAIL', 'POWERSHARE', 'PRODIGY', 'TLX', 'X400', 'GIF', 'CGM', 'WMF', 'BMP', 'MET', 'PMB', 'DIB', 'PICT', 'TIFF', 'PDF', 'PS', 'JPEG', 'QTIME', 'MPEG', 'MPEG2', 'AVI', 'WAVE', 'AIFF', 'PCM', 'X509', 'PGP'); static $values = array ( 'INLINE', 'URL', 'CID'); static $encodings = array ( '7BIT', 'QUOTED-PRINTABLE', 'BASE64'); $name = 'UNKNOWN'; if (in_array($value, $types)) { $name = 'TYPE'; } elseif (in_array($value, $values)) { $name = 'VALUE'; } elseif (in_array($value, $encodings)) { $name = 'ENCODING'; } return $name; } /** * Decodes a quoted printable value spanning multiple lines. */ function _decodeQuotedPrintable(&$lines) { $value = &$this->value; while ($value[strlen($value) - 1] == "=") { $value = substr($value, 0, strlen($value) - 1); if (!(list(, $line) = each($lines))) { break; } $value .= rtrim($line); } $value = quoted_printable_decode($value); } } // ----- Utility Functions ----- /** * Splits a string. Similar to the split function but uses a single character * delimiter and ignores delimiters in double quotes. */ function split_quoted_string($d, $s, $n = 0) { $quote = false; $len = strlen($s); for ($i = 0; $i < $len && ($n == 0 || $n > 1); $i++) { $c = $s{$i}; if ($c == '"') { $quote = !$quote; } else if (!$quote && $c == $d) { $s{$i} = "\x00"; if ($n > 0) { $n--; } } } return explode("\x00", $s); } ?> style.css : body { color: black; background: white; margin: 1em; font: normal 8pt Verdana, Arial, sans-serif; } h1 { font: bold 12pt Verdana, Arial, sans-serif; text-align: center; } h2 { font: normal 12pt Verdana, Arial, sans-serif; color: navy; margin-left: -1px; border-bottom: thin solid navy; } p { font: normal 8pt Verdana, Arial, sans-serif; } p.categories { margin-left: 2px; } p.name { padding: 2px; margin: 0; } p.property-even { background: #eee; padding: 2px; margin: 0; } p.property-odd { background: #ddd; padding: 2px; margin: 0; } td { padding: 2px; } td.vcard { border: thin solid #f99; background: #cbdced; } dt, li { margin-top: 1ex; } a { cursor: pointer } a:link { color: blue; background: transparent; text-decoration: none } a:visited { color: blue; background: transparent; text-decoration: none } a:active { color: blue; background: transparent; text-decoration: none } a:hover { color: red; background: transparent; text-decoration: underline } carddav.php : <?php include_once(dirname(__FILE__) . "/class.php"); $data = stripslashes(file_get_contents('php://input')); $data = str_replace("\"{","{",$data); $data = str_replace("}\"","}",$data); $json = json_decode($data, true); $action = $_POST['action'].$_GET['action'].$json['action']; $user = $_POST['user'].$_GET['user'].$json['user']; $password = $_POST['password'].$_GET['password'].$json['password']; $file = $_POST['file'].$_GET['file'].$json['file']; $format = $_POST['format'].$_GET['format'].$json['format']; $view = $_POST['view'].$_GET['view'].$json['view']; $option = $_POST['option'].$_GET['option'].$json['option']; if (!$file) { exit('Required $file parameter not specified.'); } if (!$action) { $action = "LIST"; //$action = "EXTRACT"; } if (!$view) { $view = "HTML"; //$view = "FILE"; } if (!$format) { $format = "XML"; //$view = "CSV"; } if (!$option) { $option = "ATR"; //$option = "VAL"; } if ($action == "LIST") { echo makeXML($user, $password, $file); } if ($action == "EXTRACT") { $lines = file($carddav_dir.$file.'.txt'); if (!$lines) { exit("Can't read the vCard file: $file"); } $cards = parse_vcards($lines); if ($format == "XML") { if ($option == "ATR") { $xml = new SimpleXMLElement('<?xml version="1.0" encoding="UTF-8" standalone="yes"?><contactData/>'); $xml->addChild('groupinfo'); $xml->addChild('blacklist'); $group = $xml->addChild('group'); foreach ($cards as $card_name => $card) { $property = $card->getProperty('FN'); $properties = $card->getProperties('TEL'); if ($properties) { foreach ($properties as $telproperty) { $types = $telproperty->params['TYPE']; if ($types) { foreach ($types as $type) { $contact = $group->addChild('contact'); $contact['sDisplayName'] = strWithoutAccent($property->getComponents()[0]).' ('.convert_french_type($type).')'; $contact['sOfficeNumber'] = $telproperty->getComponents()[0]; $contact['sMobilNumber'] = ''; $contact['sOtherNumber'] = ''; } } } } $contact['sLine'] = ''; $contact['sRing'] = ''; $contact['group'] = ''; } } if ($option == "VAL") { $xml = new SimpleXMLElement('<?xml version="1.0" encoding="ISO-8859-1"?><MyCompanyDirectory/>'); $xml->addChild('Title', 'Famille'); foreach ($cards as $card_name => $card) { $property = $card->getProperty('FN'); $properties = $card->getProperties('TEL'); if ($properties) { foreach ($properties as $telproperty) { $types = $telproperty->params['TYPE']; if ($types) { foreach ($types as $type) { $group = $xml->addChild('MenuItem'); $group->addChild('Prompt', strWithoutAccent($property->getComponents()[0]).' ('.convert_french_type($type).')'); $group->addChild('URI', $telproperty->getComponents()[0]); } } } } } } if ($view == "HTML") { Header('Content-type: text/xml; charset=utf-8'); echo ($xml->asXML()); } if ($view == "FILE") { $dom = new DOMDocument('1.0'); $dom->preserveWhiteSpace = false; $dom->formatOutput = true; $dom->loadXML($xml->asXML()); $dom->save($file.$option.'.xml'); if (file_exists($file.$option.'.xml')) { header($_SERVER["SERVER_PROTOCOL"] . " 200 OK"); header("Cache-Control: public"); // needed for i.e. header("Content-Type: application/xml; charset=utf-8"); header("Content-Transfer-Encoding: Binary"); header("Content-Length:".filesize($file.$option.'.xml')); header("Content-Disposition: attachment; filename=".$file.$option.'.xml'); readfile($file.$option.'.xml'); die(); } else { die("Error: File not found."); } } } if ($format == "CSV") { $contact = array(); foreach ($cards as $card_name => $card) { $property = $card->getProperty('FN'); $properties = $card->getProperties('TEL'); if ($properties) { foreach ($properties as $telproperty) { $types = $telproperty->params['TYPE']; if ($types) { foreach ($types as $type) { $contact[] = array($property->getComponents()[0].' ('.convert_french_type($type).')', $telproperty->getComponents()[0]); } } } } } $f = fopen($file.'.csv', 'w'); foreach ($contact as $fields) { fputcsv($f, $fields); } fclose($f); if ($view == "HTML") { echo "<html><body><table>\n\n"; $f = fopen($file.'.csv', 'r'); while (($line = fgetcsv($f)) !== false) { echo "<tr>"; foreach ($line as $cell) { echo "<td>" . htmlspecialchars($cell) . "</td>"; } echo "</tr>\n"; } fclose($f); echo "\n</table></body></html>"; } if ($view == "FILE") { if (file_exists($file.'.csv')) { header($_SERVER["SERVER_PROTOCOL"] . " 200 OK"); header("Cache-Control: public"); // needed for i.e. header("Content-Type: text/csv"); header("Content-Transfer-Encoding: Binary"); header("Content-Length:".filesize($file.'.csv')); header("Content-Disposition: attachment; filename=".$file.'.csv'); readfile($file.'.csv'); die(); } else { die("Error: File not found."); } } } } if ($action == "SHOW") { print_vcard_address_book( $carddav_dir.$file.'.txt', $_GET['title'], $_GET['style'], $_GET['cat'], $_GET['hide']); } ?> A partir de là, vous pouvez faire plusieurs choses : https://www.mondomaine.fr/carddav/carddav.php?action=LIST&file=file&user=user&password=password Permet de lancer la synchronisation (bash) à partir d'une requête web, utile si vous avez programmé une synchronisation quotidienne mais que vous voulez pouvoir le lancer à la demande https://www.mondomaine.fr/carddav/carddav.php?action=SHOW&file=file&cat=All Permet de visionner en HTML la liste des contacts https://www.mondomaine.fr/carddav/carddav.php?action=EXTRACT&file=file&format=XML&view=HTML&option=VAL Lien HTTP permettant d'extraire les données avec plusieurs paramètres : format : XML : Représentation XML CSV : Représentation CSV view : HTML : Sortie graphique FILE : Fichier téléchargé option : VAL : Fichier XML ISO-8859-1 utilisant les Valeurs pour afficher les données ATR : Fichier XML UTF-8 utilisants les Attributs pour afficher les données Mise en place du job de synchronisation Rien de plus simple, sous l'interface DSM, aller dans Panneau de Configuration, Planificateur de Tâches. Cliquer sur Créer / Script défini par l'utilisateur Donner un nom à la tâche, la faire exécuter par l'utilisateur root et renseigner le lien suivant dans Exécuter la commande : /volume1/scripts/CardDav/carddav.sh -a JOB -u user -p password -f file -s https://localhost:8443 J'ai programmé la tâche pour s'exécuter toutes les 5 minutes. A vous de voir à quel rythme vous souhaitez voir vos contacts synchronisés. Mise en place du provisioning des répertoires locaux des téléphones IP Maintenant, plus spécifiquement pour les téléphones Alcatel, nous allons mettre en place le provisionning pour 2 choses : Mise à jour des firmware Mise à jour de l'annuaire des contacts sur le téléphones Pour se faire, il suffit de déposer dans le dossier /volume1/web/tel les fichiers suivants : firmware.rom : Correspond au logiciel interne du téléphone à mettre à jour y000000000014.cfg : fichier de provisioning propre aux modèles IP600 PS : il est possible de créer des fichiers de provisionning propre à chaque tel en nommant le fichier avec l'adresse MAC du tel Le contenu du fichier y000000000014.cfg : #Version 201509301404 [ firmware ] path = /tmp/download.cfg server_type = https server_ip = server_port = login_name = login_pswd = http_url = https://www.mondomaine.fr/tel/ firmware_name = firmware.rom [ ContactList ] path = /tmp/download.cfg server_address = https://www.mondomaine.fr/tel/contactData1.xml Conclusion : Je me retrouve avec un système de gestion des contacts (perso, famille...) très complet qui me permet d'avoir mes contacts synchronisés sur les téléphones fixes, les téléphones mobiles, ma messagerie mail. Je peux alors facilement ajouter un contact en passant par la saisie dans l'interface Web de ma messagerie et le retrouver sur mon tel en déplacement ou au bureau. :) Modifié le 8 octobre 2015 par Terrano Mise à jour du carddav.sh 0 Citer Lien vers le commentaire Partager sur d’autres sites More sharing options...
Messages recommandés
Rejoindre la conversation
Vous pouvez publier maintenant et vous inscrire plus tard. Si vous avez un compte, connectez-vous maintenant pour publier avec votre compte.