Aller au contenu

Carddav : Retrouver Ses Contacts sur ses téléphones IP


Terrano

Messages recommandés

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 "&nbsp;($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>&nbsp;</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("&nbsp;", $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 :

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

Permet de visionner en HTML la liste des contacts

  

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é par Terrano
Mise à jour du carddav.sh
Lien vers le commentaire
Partager sur d’autres sites

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.

Invité
Répondre à ce sujet…

×   Collé en tant que texte enrichi.   Coller en tant que texte brut à la place

  Seulement 75 émoticônes maximum sont autorisées.

×   Votre lien a été automatiquement intégré.   Afficher plutôt comme un lien

×   Votre contenu précédent a été rétabli.   Vider l’éditeur

×   Vous ne pouvez pas directement coller des images. Envoyez-les depuis votre ordinateur ou insérez-les depuis une URL.

×
×
  • Créer...

Information importante

Nous avons placé des cookies sur votre appareil pour aider à améliorer ce site. Vous pouvez choisir d’ajuster vos paramètres de cookie, sinon nous supposerons que vous êtes d’accord pour continuer.