|
|
Ligne 1 : |
Ligne 1 : |
− | == Présentation ==
| + | Quelques exemples avec "0" comme préfixe de sortie : |
− | L'annuaire Wazo n'est pas pris en charge sur les bornes M900 en raison d'une URL Trop grande.
| + | *"0[1-3]XXX" : les numéros spéciaux Français sur 4 chiffres. |
| + | *"0118XXX" : les renseignements téléphoniques. |
| + | *"00[1-589]XXXXXXXX" : correspond aux numéros fixes français. |
| + | *"00[67]XXXXXXXX" : correspond aux numéros de cellulaires français. |
| + | *"000XXXXX." : les numéros à l'international. |
| + | *"011[23459]" : les numéros d’urgences Européen avec préfixe de sortie. |
| + | *"11[23459]" : les numéros d’urgences Européen sans préfixe de sortie |
| + | *"01[578]" : les numéros d’urgences Français avec préfixe de sortie. |
| + | *"1[578]" : les numéros d’urgences Français sans préfixe de sortie. |
| | | |
− | [[Fichier:wazo-m900snom-limitation.jpg]] | + | Quelques exemples sans préfixe de sortie : |
| + | *"[1-3]XXX" : les numéros spéciaux Français sur 4 chiffres. |
| + | *"118XXX" : les renseignements téléphoniques. |
| + | *"0[1-589]XXXXXXXX" : correspond aux numéros fixes français. |
| + | *"0[67]XXXXXXXX" : correspond aux numéros de cellulaires français. |
| + | *"00XXXXX." : les numéros à l'international. |
| + | *"11[23459]" : les numéros d’urgences Européen |
| + | *"1[578]" : les numéros d’urgences Français |
| | | |
− | Après vérification, la raison communiqué par l'éditeur wazo est exact :).
| + | [[File:Xivo_dialplan_toextern_1.png||450px]] |
| | | |
− | J'ai tenté de contourner cette limitation via une redirection 301, mais sans succès.
| + | [[File:Xivo_dialplan_toextern_2.png||450px]] |
− | | |
− | La seconde approche, qui elle fonctionne, est de télécharger ce répertoire et de le mettre à disposition sur un autre serveur avec une URL de taille accepté par les bornes.
| |
− | | |
− | Environnement de test:
| |
− | * Wazo version: 23.1
| |
− | * Borne M900 version: 530.2
| |
− | * M85 version: 530.2
| |
− | | |
− | == M900 - Phonebook ==
| |
− | Les bornes M900 peuvent gérer le répertoire distant de 4manières.
| |
− | * Local
| |
− | * LDAP
| |
− | * XML Server
| |
− | * XML MiniBrowser Server
| |
− | | |
− | === Local ===
| |
− | Ce mode télécharge le répertoire à une intervalle prédéfini et le stock dans sa mémoire.
| |
− | les téléphones récupère le répertoire sur la borne.
| |
− | | |
− | Documentation: https://service.snom.com/display/wiki/How+to+use+the+Local+Central+Directory+on+M300%2C+M700%2C+M900+DECT+base
| |
− | | |
− | === LDAP ===
| |
− | L'annuaire central du serveur LDAP permet de configurer tous les paramètres spécifiques à LDAP afin d'effectuer des recherches sur un serveur LDAP
| |
− | | |
− | === XML Server ===
| |
− | Le choix XML server est spécifique à Broadsoft , ce type de carnet d'adresses utilise une API propriétaire Broadsoft nommée XSI pour accéder aux répertoires.
| |
− | | |
− | === XML MiniBrowser Server ===
| |
− | Dans ce mode, rien n'est stocké sur la borne,
| |
− | | |
− | Quand un téléphone souhaite accéder à l'annuaire, il fait une requête http vers le serveur distant et télécharge le répertoire.
| |
− | | |
− | === Choix du type de serveur ===
| |
− | De base, wazo est fait pour fonctionner avec XML Minibrowser Server, mais lors de mes différents test j'ai pu constater qu'un annuaire de plus de 160 contacts n'était pas accepté.
| |
− | | |
− | Le mode Local n'ayant pas cette limitation nous adapteront le fichier xml afin de lui convenir.
| |
− | | |
− | ==Configuration du serveur==
| |
− | === VM ===
| |
− | Dans mon cas, je suis parti avec une VM:
| |
− | * Stockage: 4Go
| |
− | * Rem: 1024Mo
| |
− | | |
− | Sur laquelle j'ai installé une Debian 11.6 minimal avec serveur web (apache2) + php
| |
− | | |
− | === Page Web ===
| |
− | Dans notre cas le repertoire apache racine est:
| |
− | /var/www/html
| |
− | | |
− | Création des repertoires
| |
− | mkdir /var/www/html/includes
| |
− | mkdir /var/www/html/download
| |
− | | |
− | Mise en place des droits pour appaches
| |
− | chown www-data:www-data /var/www/html
| |
− | chown www-data:www-data /var/www/html/includes
| |
− | | |
− | Créer un fichier de redirection pour l'index
| |
− | vi /var/www/html/index.php
| |
− | | |
− | <nowiki><?php
| |
− | header("Status: 301 Moved Permanently", false, 301);
| |
− | header("Location: https://www.oci.fr/oci-connect/");
| |
− | exit();
| |
− | ?></nowiki>
| |
− | | |
− | Créer la page d'administration en remplaçant bien sur le mot de passe : VOTRE_MOT_DE_PASSE par le votre en ligne 8
| |
− | vi /var/www/html/phonebook.php
| |
− | | |
− | <nowiki><?php
| |
− | session_start();
| |
− | | |
− | // Vérifier si le mot de passe a été soumis
| |
− | if (isset($_POST['mot_de_passe'])) {
| |
− | $motDePasseSaisi = $_POST['mot_de_passe'];
| |
− | // Comparer le mot de passe saisi avec le mot de passe souhaité
| |
− | if ($motDePasseSaisi === 'VOTRE_MOT_DE_PASSE') {
| |
− | // Mot de passe correct, définir une variable de session pour indiquer que l'utilisateur est authentifié
| |
− | $_SESSION['authentifie'] = true;
| |
− | } else {
| |
− | // Mot de passe incorrect, afficher un message d'erreur
| |
− | echo "Mot de passe incorrect.";
| |
− | }
| |
− | }
| |
− | | |
− | // Vérifier si l'utilisateur est authentifié
| |
− | if (!isset($_SESSION['authentifie']) || $_SESSION['authentifie'] !== true) {
| |
− | // Afficher le formulaire de saisie du mot de passe
| |
− | echo '<form method="post" action="">';
| |
− | echo 'Mot de passe : <input type="password" name="mot_de_passe">';
| |
− | echo '<input type="submit" value="Valider">';
| |
− | echo '</form>';
| |
− | } else {
| |
− | // Afficher le contenu protégé
| |
− | echo "Contenu protégé : les utilisateurs authentifiés peuvent voir ce contenu.";
| |
− | | |
− | // Vérification si le formulaire a été soumis
| |
− | if ($_SERVER["REQUEST_METHOD"] == "POST") {
| |
− | // Récupération des valeurs soumises
| |
− | $valeurs1 = isset($_POST["valeur1"]) ? $_POST["valeur1"] : array();
| |
− | $valeurs2 = isset($_POST["valeur2"]) ? $_POST["valeur2"] : array();
| |
− | $valeurs3 = isset($_POST["valeur3"]) ? $_POST["valeur3"] : array();
| |
− | $valeurs4 = isset($_POST["valeur4"]) ? $_POST["valeur4"] : array();
| |
− | | |
− | // Formatage des valeurs en tableau associatif
| |
− | $donnees = array();
| |
− | for ($i = 0; $i < count($valeurs1); $i++) {
| |
− | // Génération du hash en utilisant la valeur de la colonne 2
| |
− | $hash = hash('sha256', $valeurs2[$i]);
| |
− | // Encodage du hash en base64
| |
− | $base64 = base64_encode($hash);
| |
− | // Extraction des 16 premiers caractères de l'encodage en base64
| |
− | $valeur4 = substr($base64, 0, 16);
| |
− | | |
− | $donnees[$i] = array(
| |
− | "valeur1" => isset($valeurs1[$i]) ? "checked" : "",
| |
− | "valeur2" => $valeurs2[$i],
| |
− | "valeur3" => $valeurs3[$i],
| |
− | "valeur4" => $valeur4
| |
− | );
| |
− | }
| |
− | | |
− | // Écriture des données dans le fichier variables.json
| |
− | $contenu = json_encode($donnees);
| |
− | file_put_contents("includes/variables.json", $contenu);
| |
− | } else {
| |
− | // Si le formulaire n'a pas été soumis, vérifier si le fichier variables.json existe
| |
− | if (file_exists("includes/variables.json")) {
| |
− | // Charger les données depuis le fichier variables.json
| |
− | $contenu = file_get_contents("includes/variables.json");
| |
− | $donnees = json_decode($contenu, true);
| |
− | }
| |
− | }
| |
− | ?>
| |
− |
| |
− | <!DOCTYPE html>
| |
− | <html>
| |
− | <head>
| |
− | <title>OCI - Phonebook</title>
| |
− | <style>
| |
− | /* Styles pour agrandir les champs de texte des colonnes 3 et 4 */
| |
− | .large-input {
| |
− | width: 300px;
| |
− | }
| |
− | /* Styles pour le tableau */
| |
− | body {
| |
− | font-family: Arial, sans-serif;
| |
− | background-color: #F8F8F8;
| |
− | }
| |
− | h1 {
| |
− | text-align: center;
| |
− | color: #333;
| |
− | }
| |
− | table {
| |
− | width: 100%;
| |
− | max-width: 800px;
| |
− | margin: 0 auto;
| |
− | border-collapse: collapse;
| |
− | background-color: #FFF;
| |
− | box-shadow: 0px 2px 4px rgba(0, 0, 0, 0.1);
| |
− | }
| |
− | th, td {
| |
− | padding: 10px;
| |
− | text-align: left;
| |
− | }
| |
− | th {
| |
− | background-color: #333;
| |
− | color: #FFF;
| |
− | }
| |
− | tr:nth-child(even) {
| |
− | background-color: #F8F8F8;
| |
− | }
| |
− | tr:hover {
| |
− | background-color: #EAEAEA;
| |
− | }
| |
− | input[type="submit"] {
| |
− | display: block;
| |
− | margin: 20px auto;
| |
− | padding: 10px 20px;
| |
− | font-size: 16px;
| |
− | color: #FFF;
| |
− | background-color: #333;
| |
− | border: none;
| |
− | cursor: pointer;
| |
− | }
| |
− | input[type="submit"]:hover {
| |
− | background-color: #555;
| |
− | }
| |
− | .readonly {
| |
− | background-color: #F8F8F8;
| |
− | color: #999;
| |
− | }
| |
− | .copy-btn {
| |
− | display: inline-block;
| |
− | vertical-align: middle;
| |
− | margin-left: 10px;
| |
− | padding: 5px 10px;
| |
− | background-color: #333;
| |
− | color: #FFF;
| |
− | border: none;
| |
− | cursor: pointer;
| |
− | }
| |
− | .copy-btn:hover {
| |
− | background-color: #555;
| |
− | }
| |
− | </style>
| |
− | </head>
| |
− | <body>
| |
− | <h1>Phonebook Wazo pour Snom</h1>
| |
− | <form method="post" action="<?php echo $_SERVER["PHP_SELF"]; ?>">
| |
− | <table>
| |
− | <tr>
| |
− | <th>#</th>
| |
− | <th>Activer</th>
| |
− | <th>Nom du client</th>
| |
− | <th>URL Annuaire Wazo</th>
| |
− | <th>ID nouvel annuaire</th>
| |
− | <th></th>
| |
− | </tr>
| |
− | <?php for ($i = 0; $i < 100; $i++) { ?>
| |
− | <tr>
| |
− | <td><?php echo $i + 1; ?></td>
| |
− | <td><input type="checkbox" name="valeur1[]" <?php echo isset($donnees[$i]["valeur1"]) ? $donnees[$i]["valeur1"] : ''; ?>></td>
| |
− | <td><input type="text" name="valeur2[]" value="<?php echo isset($donnees[$i]["valeur2"]) ? $donnees[$i]["valeur2"] : ''; ?>"></td>
| |
− | <td><input type="text" name="valeur3[]" value="<?php echo isset($donnees[$i]["valeur3"]) ? $donnees[$i]["valeur3"] : ''; ?>" class="large-input"></td>
| |
− | <td><input type="text" name="valeur4[]" value="<?php echo isset($donnees[$i]["valeur4"]) ? $donnees[$i]["valeur4"] : ''; ?>" class="large-input readonly" readonly></td>
| |
− | <td><input type="button" value="Copier ID" class="copy-btn" onclick="copyToClipboard(this)"></td>
| |
− | </tr>
| |
− | <?php } ?>
| |
− | </table>
| |
− | <input type="submit" value="Enregistrer">
| |
− | </form>
| |
− | <script>
| |
− | // Fonction pour copier le contenu d'un champ de texte dans le presse-papier
| |
− | function copyToClipboard(button) {
| |
− | var input = button.parentNode.previousElementSibling.firstElementChild;
| |
− | input.select();
| |
− | input.setSelectionRange(0, 99999);
| |
− | document.execCommand("copy");
| |
− | }
| |
− | </script>
| |
− | </body>
| |
− | </html>
| |
− | <!-- Fin du contenu HTML protégé -->
| |
− | <?php
| |
− | }
| |
− | ?>
| |
− | </nowiki>
| |
− | | |
− | === Script ===
| |
− | Nous allons installer 2 scripts
| |
− | # Télécharger les répertoires wazo
| |
− | # Adapter les répertoires téléchargés
| |
− | | |
− | mkdir /etc/phonebook
| |
− | | |
− | ==== Télécharger les répertoires ====
| |
− | vi /etc/phonebook/download.sh
| |
− | | |
− | <nowiki>#!/bin/bash
| |
− | | |
− | # Charger les données depuis le fichier variables.json
| |
− | contenu=$(cat /var/www/html/includes/variables.json)
| |
− | donnees=($(echo "$contenu" | jq -r '.[] | "\(.valeur1),\(.valeur2),\(.valeur3),\(.valeur4)"'))
| |
− | | |
− | # Parcourir les données et télécharger les fichiers
| |
− | for donnee in "${donnees[@]}"; do
| |
− | # Extraire les valeurs de chaque colonne
| |
− | valeur1=$(echo "$donnee" | cut -d ',' -f 1)
| |
− | valeur3=$(echo "$donnee" | cut -d ',' -f 3)
| |
− | valeur4=$(echo "$donnee" | cut -d ',' -f 4)
| |
− | | |
− | # Vérifier si la case de la colonne 1 est activée
| |
− | if [ "$valeur1" == "checked" ]; then
| |
− | # Télécharger le fichier avec wget
| |
− | wget "$valeur3" -O "/var/www/html/phonebook/$valeur4"
| |
− | echo "Le fichier $valeur4 a été téléchargé depuis $valeur3."
| |
− | fi
| |
− | done
| |
− | </nowiki>
| |
− | | |
− | Donner les droits d'exécution
| |
− | chmod +x /etc/phonebook/download.sh
| |
− | | |
− | ==== Adapter les répertoires ====
| |
− | vi /etc/phonebook/custom.sh
| |
− | | |
− | <syntaxhighlight lang="shell" line highlight="9-11">#!/bin/bash
| |
− | # Scrypt lancé par crontab
| |
− | | |
− | sleep 5
| |
− | | |
− | #Remplacer les caractères non apprecié
| |
− | sed -i 's/'/ /' /var/www/html/phonebook/*
| |
− | sed -i 'y/_àçéèêëîïôöùüÂÇÉÈÊËÎÏÔÖÙÜ/ aceeeeiioouuACEEEEIIOOUU/' /var/www/html/phonebook/*
| |
− | | |
− | ## Adapter au format Tbook
| |
− | sed -i 's#/SnomIPPhoneDirectory#/tbook#' /var/www/html/phonebook/*
| |
− | sed -i 's/SnomIPPhoneDirectory/tbook complete="true"/' /var/www/html/phonebook/*
| |
− | | |
− | sed -i 's#/DirectoryEntry#/item#' /var/www/html/phonebook/*
| |
− | sed -i 's/DirectoryEntry/item context="active" type="colleagues"/' /var/www/html/phonebook/*
| |
− | | |
− | sed -i 's#/Name>#/name>#' /var/www/html/phonebook/*
| |
− | sed -i 's/Name>/name>/' /var/www/html/phonebook/*
| |
− | | |
− | sed -i 's#/Telephone>#/number>#' /var/www/html/phonebook/*
| |
− | sed -i 's/Telephone>/number>/' /var/www/html/phonebook/*
| |
− | </syntaxhighlight>
| |
− | | |
− | Donner les droits d'exécution
| |
− | chmod +x /etc/phonebook/custom.sh
| |
− | | |
− | ==== Planifier l'exécution des scripts ====
| |
− | Dans l'exemple ci-dessous les répertoires seront mis à jours toute les 5 minutes
| |
− | crontab -e
| |
− | | |
− | # Télécharger les répertoires
| |
− | */5 * * * * sh /etc/phonebook/download.sh > /dev/null
| |
− | | |
− | # Adapter les répertoires
| |
− | */5 * * * * sh /etc/phonebook/custom.sh > /dev/null
| |
− | | |
− | == Configuration des bornes snom ==
| |
− | === Méthode Manuel ===
| |
− | Voici les paramètres à configurer sur la borne maitre afin que la borne à télécharger son annuaire toute les 5minutes
| |
− | | |
− | Attention, si le provisionning est activé avec une configuration différente, les paramètres seront écrasés.
| |
− | | |
− | PI: Le bouton "charger" permet de vider le répertoire actuel
| |
− | | |
− | [[Fichier:wazo-m900snom-manuel.jpg]]
| |
− | | |
− | === Autoprovisionning Wazo ===
| |
− | | |
− | La méthode "propre" est de créer une template custom pour la borne M900
| |
− | | |
− | ci dessous un lien vers la documentation wazo:
| |
− | | |
− | https://wazo-platform.org/documentation/overview/provisioning-admin.html
| |
− | | |
− | Les champs nous intéressant sont:
| |
− | en ligne 56 le type de repertoire (O = Local, 1 LDAP, 2 XML Server, 3 XML browser server)
| |
− | <phonebook_server_location perm="R">0</phonebook_server_location>
| |
− | | |
− | en ligne 57 l'adresse du serveur
| |
− | <phonebook_location perm="R">https://phonebook.slemoal.fr/</phonebook_location>
| |
− | | |
− | le nouveau fichier M900.tpl devra ressembler à celui la:
| |
− | | |
− | <nowiki><?xml version="1.0" encoding="utf-8" ?>
| |
− | <settings>
| |
− | <phone-settings>
| |
− | {%- if vlan_enabled %}
| |
− | <vlan_id>{{ vlan_id }}</vlan_id>
| |
− | <vlan_qos>{{ vlan_priority|d('0') }}</vlan_qos>
| |
− | {%- else %}
| |
− | <vlan_id></vlan_id>
| |
− | <vlan_qos></vlan_qos>
| |
− | {%- endif %}
| |
− | | |
− | <codec_tos>184</codec_tos>
| |
− | <codec_priority_list perm="R">pcma,pcmu,g722,g729,telephone-event</codec_priority_list>
| |
− | <signaling_tos>184</signaling_tos>
| |
− | | |
− | {%- if admin_username %}
| |
− | <http_user>{{ admin_username|e }}</http_user>
| |
− | {%- else %}
| |
− | <http_user>guest</http_user>
| |
− | {%- endif %}
| |
− | | |
− | {%- if admin_password %}
| |
− | <admin_mode_password>{{ admin_password|e }}</admin_mode_password>
| |
− | <http_pass>{{ admin_password|e }}</http_pass>
| |
− | {%- else %}
| |
− | <admin_mode_password>12345</admin_mode_password>
| |
− | <http_pass>guest</http_pass>
| |
− | {%- endif %}
| |
− | | |
− | {%- if ntp_enabled %}
| |
− | <ntp_server>{{ ntp_ip }}</ntp_server>
| |
− | {%- else %}
| |
− | <ntp_server></ntp_server>
| |
− | {%- endif %}
| |
− | | |
− | {%- for server in XX_servers.values() %}
| |
− | <srv_sip_server_alias idx="{{ server['id'] }}">Wazo {{ server['id'] }}</srv_sip_server_alias>
| |
− | <user_host idx="{{ server['id'] }}">{{ server['proxy_ip'] }}</user_host>
| |
− | <srv_srtp_auth idx="{{ server['id'] }}">off</srv_srtp_auth>
| |
− | <user_dtmf_info idx="{{ server['id'] }}">{{ server['dtmf_mode'] }}</user_dtmf_info>
| |
− | {%- endfor %}
| |
− | | |
− | {%- for line_no, line in sip_lines.items() %}
| |
− | <user_active idx="{{ line_no }}">on</user_active>
| |
− | <user_name idx="{{ line_no }}">{{ line['username']|e }}</user_name>
| |
− | <user_pname idx="{{ line_no }}">{{ line['auth_username']|e }}</user_pname>
| |
− | <user_pass idx="{{ line_no }}">{{ line['password']|e }}</user_pass>
| |
− | <user_realname idx="{{ line_no }}">{{ line['display_name']|e }}</user_realname>
| |
− | <user_mailbox idx="{{ line_no }}">{{ line['voicemail'] }}</user_mailbox>
| |
− | <subscr_sip_hs_idx idx="{{ line_no }}">{{ line_no }}</subscr_sip_hs_idx>
| |
− | <subscr_dect_ac_code idx="{{ line_no }}">{{ "{0:0>4}".format(line_no) }}</subscr_dect_ac_code>
| |
− | <subscr_sip_ua_data_server_id idx="{{ line_no }}">{{ line['XX_server_id'] }}</subscr_sip_ua_data_server_id>
| |
− | <codec_priority_list idx="{{ line_no }}" perm="R">pcma,pcmu,g722,g729,telephone-event</codec_priority_list>
| |
− | {%- endfor %}
| |
− | | |
− | {% if XX_xivo_phonebook_url -%}
| |
− | <phonebook_server_location perm="R">0</phonebook_server_location>
| |
− | <phonebook_location perm="R">https://phonebook.slemoal.fr/</phonebook_location>
| |
− | {% endif -%}
| |
− | | |
− | {%- if XX_lang %}
| |
− | <language>{{ XX_lang[0] }}</language>
| |
− | <web_language>{{ XX_lang[0] }}</web_language>
| |
− | <tone_scheme>{{ XX_lang[1] }}</tone_scheme>
| |
− | {%- endif %}
| |
− | | |
− | {% block settings_suffix %}{% endblock %}
| |
− | </phone-settings>
| |
− | </settings>
| |
− | </nowiki>
| |
− | | |
− | Une fois la borne autoprovisionner, vous devrez vous connecter sur la borne maitre et renseigner le nom du fichier xml (phonebook-nomduclient.xml)
| |
− | | |
− | [[Fichier:wazo-m900snom-auto.jpg]]
| |