Il y a quelques temps je vous ai expliqué la stratégie que j’ai mise en place pour synchroniser un fichier ICS (iCal) avec un calendrier sous Google Agenda. La méthode est simple, elle s’appuie sur un script Perl (auquel j’ai apporté depuis quelques petites modifications) et des modules que vous pouvez installer via CPAN.
Maintenons compliquons le problème avec plusieurs calendriers à synchroniser. La méthode la plus simple est de programmer dans notre Crontab
(au via LaunchDaemon
sur OS X) autant de tâches que de calendriers à synchroniser, en passant lançant une commande par calendrier comme indiqué mon article précédent.
J’ai préféré de mon côté mettre en place un script Bash “parent” qui se chargera de lire un fichier de configuration spécifique contenant la liste de calendriers à synchroniser. L’avantage est d’avoir un fichier texte avec votre configuration que vous pourrez modifier à tout moment. J’en ai profité pour fiabiliser un peu le processus en ajoutant quelques tests et en utilisant également un autre sous-script chargé de nettoyer le fichier ICS des rappels (alarmes) et des tâches pour que cela soit plus propre dans Google Calendar.
Le principe
Le principe que j’ai retenu est simple. Je rassemble mes scripts dans un dossier /usr/local/bin/kerio-ics-to-gcal
.
A l’intérieur je vais déposer un script “parent” en Bash : ics-sync.sh
. Ce script va lire un fichier ics-sync-script.conf
dans le dossier /etc
. Ce dernier fichier de configuration va contenir une ligne par calendrier à synchroniser avec :
- l’URL du calendrier à synchroniser,
- le nom du fichier temporaire local qui sera créé,
- la référence au compte Google Calendar (telle que stockée dans votre fichier ~./netrc),
- le nom du Calendrier Google Agenda avec lequel synchroniser.
Notre script ics-sync.sh
va effectuer, pour chaque ligne de ce fichier de configuration, les actions suivantes :
- quelques tests pour vérifier que l’URL du fichier ICS à synchroniser est joignable et qu’elle renvoie un fichier ICS valide,
- le fichier ICS est ensuite téléchargé dans un dossier (variable
$PATH_FILES
). Notez que ce dossier doit être joignable depuis une url pour la suite du processus. Je ne détaillerai pas ici la configuration nécessaire (mais vous trouverez sans souci avec votre ami au grand G). - le fichier ICS est ensuite “nettoyé” grâce à un script Python (trouvé ici) : le fichier est nettoyé des éventuelles alarmes (rappels) et des tâches.
- le fichier est ensuite synchronisé avec votre calendrier Google, selon la méthode que j’avais décrite.
C’est un peu tordu et protéiforme car, n’étant pas informaticien et peu fainéant, j’utilise ici des scripts d’autres auteurs, mais ça marche.
Etape 1 : mise en place du dossier et du fichier ~/.netrc
Pour commencer il nous faut préparer le dossier où nous allons déposer nos trois scripts, ici /usr/local/bin/kerio-ics-to-gcal
. Dans votre terminal, faites sudo mkdir -p /usr/local/bin/kerio-ics-to-gcal
pour créer ce dossier.
Nous allons maintenant stocker les différentes informations de connexion dans le fichier ~./netrc
du compte root
. Depuis votre terminal, faites :
sudo su # uniquement si vous n'êtes pas connecté en root nano ~./netrc
Pour chaque compte à configurer, il vous faut entrer trois lignes, commençant par machine
, login
, password
.
machine nomducompte
login monadresse@gcalendar.com
password monsupermotdepasse
Pour configurer deux comptes votre fichier devrait ressembler à ceci :
machine moncompte_googlecalendar_1 login monadresse@gcalendar.com password monsupermotdepasse machine moncompte_googlecalendar_2 login monadresse@moi.me password mondeuxiememotdepassesupersolide
Une fois que vous avez entré les informations faites un petit [CTRL] + X
pour sortir, et n’oubliez pas de valider l’enregistrement par Yes
puis [Enter]
. Ensuite, pour sécuriser un peu ce fichier sensible, n’oubliez pas de faire sudo chmod 600 ~/.netrc
.
Etape 2 : installer et lancer le sous-script Perl
La deuxième chose à faire est d’installer le sous-script Perl qui va gérer la synchronisation à proprement parler. Avant de passer à la suite, je vous invite donc à vous reporter à mon billet précédent et le suivre en totalité. Assurez-vous d’arriver à synchroniser un calendrier avant de passer à la suite.
Etape 3 : récupérons le script de nettoyage
Une fois que vous arrivez à obtenir une synchronisation, il va vous falloir récupérer le script Python https://github.com/emeidi/ical-to-gcal.
Pour cela, depuis votre terminal :
cd /usr/local/bin/kerio-ics-to-gcal sudo wget https://raw.github.com/emeidi/ical-to-gcal/master/ical-to-gcal.py sudo chmod 755 ical-to-gcal.py
Etape 4 : préparer le fichier de configuration /etc/ics-sync-script.conf
Créez avec l’éditeur de votre choix ce fichier de configuration. Il contiendra une ligne par calendrier à synchronisation. Sur cette ligne vous devez entrer quatre paramètres, séparés par des tabulations dans l’ordre suivant :
- URL du fichier ICS
- Nom de fichier en local
- Compte Google Calendar à utiliser, tel qu’il apparait dans le fichier
~/.netrc
(exemplemoncompte_googlecalendar_2
pour utiliser nos deuxièmes identifiants de connexion dans l’exemple de l’étape 1) - Nom du Calendrier Google, attention c’est sensible à la casse et vous devez vérifier que votre calendrier a bien été créé sur le compte Google correspondant avant de commencer.
Cela peut donner par exemple :
http://media.education.gouv.fr/ics/Calendrier_Scolaire_Zone_A.ics ZONEA moncompte_googlecalendar_2 VacancesZoneA
Etape 5 : mettre en place le script parent
Pour terminer, il nous reste à mettre en place le script qui va orchestrer l’ensemble. Lancer dans votre terminal, puis faites sudo nano /usr/local/bin/kerio-ics-to-gcal/ics-sync.sh
.
Collez le contenu suivant, en adaptant les variables à votre configuration :
$CONFIG_FILE
contiendra l’emplacement de votre fichier de configuration. Si vous ne le déposez pas, comme convenu à l’étape 4, à l’emplacement/etc/ics-sync-script.conf
, il faudra modifier cette variable ;$PATH_FILES
contiendra l’emplacement des fichiers ICS téléchargés en local, ce dossier devant être joignable en HTTP ;$WEB_PATH_ICS
contiendra l’URL permettant de joindre sur le web le dossier$PATH_FILES
;$LOGS_GEN
contiendra l’emplacement des journaux du script, par défaut ici/var/log/ics_sync.log
$MAIL_ADMIN
contiendra l’adresse email pour les rapports d’exécution ;$MAIL_SENDER
contiendra l’adresse email d’expéditeur pour les rapports d’exécution.
Vous n’avez normalement pas à modifier les autres variables.
#!/bin/bash SCRIPT_NAME=$(basename $0) SCRIPT_DIR=$(dirname $0) # Thanks to https://github.com/emeidi/ical-to-gcal | cf. Etape 3 https://www.yvangodard.fr/synchroniser-plusieurs-fichiers-ics-ical-avec-des-calendriers-google-agenda PYTHON_ICS_CLEANER=${SCRIPT_DIR}/cleaner-ics-to-gcal.py # Thanks to https://github.com/bigpresh/ical-to-google-calendar | need some modifications => https://github.com/yvangodard/ical-to-google-calendar # Cf. cf. Etape 2 https://www.yvangodard.fr/synchroniser-plusieurs-fichiers-ics-ical-avec-des-calendriers-google-agenda PERL_SYNC_SCRIPT=${SCRIPT_DIR}/ical-to-gcal.pl SCR_VERS="1.0" # cf. Etape 4 https://www.yvangodard.fr/synchroniser-plusieurs-fichiers-ics-ical-avec-des-calendriers-google-agenda CONFIG_FILE=/etc/ics-sync-script.conf # Répertoire où seront stockés les fichiers ICS en "transit". Ce répertoire doit être joignable via le procoloe HTTP. PATH_FILES=/home/webserver OWNER_PATH_ICS=$(stat -c %U $PATH_FILES) GWNER_PATH_ICS=$(stat -c %G $PATH_FILES) PATH_ICS=$PATH_FILES/ical # Emplacement sur le web de votre dossier $PATH_ICS WEB_PATH_ICS=http://monserveur.web/ical DATE_DU_JOUR=$(date) LOGS_TMP=$(mktemp /tmp/tmp_log_ics_sync.XXXXX) LOGS_MAIL=$(mktemp /tmp/tmp_log_ics_sync_mail.XXXXX) LOGS_GEN=/var/log/ics_sync.log MAIL_ADMIN="monmail@alerte.com" MAIL_SENDER="homer@thesimpsons.net" ERROR_GEN=0 ERROR_FILE=$(mktemp /tmp/tmp_log_ics_sync_error.XXXXX) ERROR=0 FORCEMAIL=0 [ -z "$1" ] || { case $1 in "-forcemail" ) FORCEMAIL=1 ;; "-version" ) echo "${SCRIPT_NAME} version ${SCR_VERS}" ;; * ) esac } ## Vérifions que le script soit exécuté par le compte root if [ `whoami` != 'root' ] then echo "Ce script doit être utilisé par le compte root. Utilisez SUDO." >&2 exit 1 fi [ ! -e $LOGS_GEN ] && echo " " >> $LOGS_GEN # Ouvrons une ligne dans le log temporaire echo " " >> $LOGS_TMP echo "****************************** $DATE_DU_JOUR ******************************" >> $LOGS_TMP echo " " >> $LOGS_TMP # Par sécurité créons le dossier [ ! -d $PATH_ICS ] && mkdir -p $PATH_ICS # Testons si les éléments de configuration nécessaires sont présents if [ ! -e $CONFIG_FILE ]; then echo "ERREUR : Le fichier de configuration $CONFIG_FILE n'existe pas !!!" >> $LOGS_TMP echo >> $LOGS_TMP echo "Voici un exemple de configuration :" >> $LOGS_TMP echo "# Format des lignes :" >> $LOGS_TMP echo "# URL_du_calendrier Nom_fichier Entree_Config_netrc Calendar_GCAL" >> $LOGS_TMP echo "http://mon.adresse/mon/fichier/ics fichier_test calendar.google.com MonCalendrierGooglePro" >> $LOGS_TMP echo "https://webmail.reseauenscene.fr/ical/reseauenscene.fr/t.grospiron/Projet%20CultiZer CultiZer calendar.google.com CultiZer_Reunions" >> $LOGS_TMP echo "https://serveur.reseauenscene.fr/ical/reseauenscene.fr/t.grospiron/Calendrier TGPro calendar.google.com Thomas_Grospiron_Pro" >> $LOGS_TMP ERROR_GEN=1 elif [ ! -e ~/.netrc ]; then echo "ERREUR : Le fichier de configuration ~/.netrc n'existe pas !!!" >> $LOGS_TMP echo >> $LOGS_TMP echo "Voici un exemple de configuration :" >> $LOGS_TMP echo "machine ftp.freebsd.org" >> $LOGS_TMP echo " login anonymous" >> $LOGS_TMP echo " password edwin@mavetju.org" >> $LOGS_TMP echo >> $LOGS_TMP echo "machine myownmachine" >> $LOGS_TMP echo " login myusername" >> $LOGS_TMP echo " password mypassword" >> $LOGS_TMP ERROR_GEN=1 # Testons si les sous-scripts sont présents elif [ ! -e $PYTHON_ICS_CLEANER ]; then echo "ERREUR : Le sous-script $PYTHON_ICS_CLEANER n'existe pas !!!" >> $LOGS_TMP echo "Installez-le à partir de https://github.com/emeidi/ical-to-gcal et renommez-le correctement." >> $LOGS_TMP ERROR_GEN=1 elif [ ! -e $PERL_SYNC_SCRIPT ]; then echo "ERREUR : Le sous-script $PERL_SYNC_SCRIPT n'existe pas !!!" >> $LOGS_TMP echo "Installez-le à partir de https://github.com/yvangodard/ical-to-google-calendar." >> $LOGS_TMP ERROR_GEN=1 else cat $CONFIG_FILE | \ while read URL_CALENDAR LOCAL_FILE NETRC_CONFIG CALENDAR_GCAL do ERROR_PART=0 echo " --> Traitement de l'URL : $URL_CALENDAR" >> $LOGS_TMP echo "" >> $LOGS_TMP ## Testons si les quatre variables nécessaires sont présentes VAR_OK=0 if [ "1${CALENDAR_GCAL}" = "1" ]; then VAR_OK=1 echo "Erreur : les quatre variables nécessaires ne sont pas présentes." >> $LOGS_TMP && ERROR=1 echo "Voici un exemple de configuration :" >> $LOGS_TMP echo "# Format des lignes :" >> $LOGS_TMP echo "# URL_du_calendrier Nom_fichier Entree_Config_netrc Calendar_GCAL" >> $LOGS_TMP echo "http://media.education.gouv.fr/ics/Calendrier_Scolaire_Zone_A.ics ZONEA moncompte_googlecalendar_2 VacancesZoneA" >> $LOGS_TMP echo "http://media.education.gouv.fr/ics/Calendrier_Scolaire_Zone_B.ics ZONEB moncompte_googlecalendar_1 VacancesZoneB" >> $LOGS_TMP echo "http://media.education.gouv.fr/ics/Calendrier_Scolaire_Zone_C.ics ZONE_C_Vacances moncompte_googlecalendar_1 VacancesZoneC" >> $LOGS_TMP fi if [ $VAR_OK -eq 0 ]; then ## Testons si l'URL est correcte curl -k -s --head $URL_CALENDAR | head -n 1 | grep "HTTP/1.1 200 OK" > /dev/null URL_OK=$? [ $URL_OK -eq 0 ] && echo "URL du calendrier semble OK : $URL_CALENDAR." >> $LOGS_TMP [ $URL_OK -ne 0 ] && echo "Problème possible pour accéder à l'URL du calendrier : $URL_CALENDAR." >> $LOGS_TMP ## Testons si l'entrée dans le fichier ~/.netrc semble correcte grep $NETRC_CONFIG ~/.netrc > /dev/null GREP_NETRC=$? [ $GREP_NETRC -eq 0 ] && echo "Entrée $NETRC_CONFIG du fichier ~/.netrc semble correcte." >> $LOGS_TMP [ $GREP_NETRC -ne 0 ] && echo "Entrée $NETRC_CONFIG manquante dans le fichier ~/.netrc." >> $LOGS_TMP && ERROR_PART=1 else ERROR_PART=1 fi ## Continuons notre processus si nous n'avons pas rencontré d'erreur if [ $ERROR_PART -ne 0 ]; then echo " --> Impossible de continuer le traitement de l'URL : $URL_CALENDAR." >> $LOGS_TMP && ERROR=1 else [ -e ${PATH_ICS}/${LOCAL_FILE}.ics ] && rm ${PATH_ICS}/${LOCAL_FILE}.ics [ -e ${PATH_ICS}/${LOCAL_FILE}.gcal.ics ] && rm ${PATH_ICS}/${LOCAL_FILE}.gcal.ics curl -k --silent $URL_CALENDAR -o ${PATH_ICS}/${LOCAL_FILE}.ics && chown -R $OWNER_PATH_ICS:$GWNER_PATH_ICS $PATH_ICS ## Testons si le fichier semble correct (contient BEGIN:VCALENDAR) if [ -e ${PATH_ICS}/${LOCAL_FILE}.ics ]; then cat ${PATH_ICS}/${LOCAL_FILE}.ics | head -n 10 | grep "BEGIN:VCALENDAR" > /dev/null ICS_OK=$? else ICS_OK=1 fi if [ $ICS_OK -ne 0 ]; then echo "Le fichier ${PATH_ICS}/${LOCAL_FILE}.ics ne semble pas être un ICS valide." >> $LOGS_TMP echo " --> Impossible de continuer le traitement de l'URL : $URL_CALENDAR." >> $LOGS_TMP && ERROR=1 else echo "Le fichier ${PATH_ICS}/${LOCAL_FILE}.ics semble correct." >> $LOGS_TMP ## Préparons le fichier pour la synchro GCAL echo "" >> $LOGS_TMP echo "Envoi de la commande $PYTHON_ICS_CLEANER ${PATH_ICS}/${LOCAL_FILE}.ics." >> $LOGS_TMP echo "" >> $LOGS_TMP echo "***********" >> $LOGS_TMP $PYTHON_ICS_CLEANER ${PATH_ICS}/${LOCAL_FILE}.ics >> $LOGS_TMP 2>&1 ERROR_PART2=$? echo "***********" >> $LOGS_TMP echo "" >> $LOGS_TMP if [ $ERROR_PART2 -ne 0 ]; then echo "Le fichier ${PATH_ICS}/${LOCAL_FILE}.ics n'a pas été traité correctement par $PYTHON_ICS_CLEANER." >> $LOGS_TMP echo " --> Impossible de continuer le traitement de l'URL : $URL_CALENDAR." >> $LOGS_TMP && ERROR=1 else echo "Le fichier ${PATH_ICS}/${LOCAL_FILE}.ics a été traité correctement par $PYTHON_ICS_CLEANER." >> $LOGS_TMP ## Continuons notre processus si nous n'avons pas rencontré d'erreur echo "" >> $LOGS_TMP echo "Envoi de la commande $PERL_SYNC_SCRIPT --calendar=${CALENDAR_GCAL} --ical_url=${WEB_PATH_ICS}/${LOCAL_FILE}.gcal.ics --configmachine=${NETRC_CONFIG}." >> $LOGS_TMP echo "" >> $LOGS_TMP echo "***********" >> $LOGS_TMP /usr/bin/perl $PERL_SYNC_SCRIPT --calendar=${CALENDAR_GCAL} --ical_url=${WEB_PATH_ICS}/${LOCAL_FILE}.gcal.ics --configmachine=${NETRC_CONFIG} >> $LOGS_TMP 2>&1 ERROR_PART3=$? echo "***********" >> $LOGS_TMP echo "" >> $LOGS_TMP if [ ${ERROR_PART3} -eq 0 ]; then echo "Le fichier ${PATH_ICS}/${LOCAL_FILE}.gcal.ics a été traité correctement par la commande $PERL_SYNC_SCRIPT." >> $LOGS_TMP else echo "Erreur(s) lors de l'envoi de la commande $PERL_SYNC_SCRIPT." >> $LOGS_TMP echo " --> Impossible de terminer le traitement de l'URL : $URL_CALENDAR." >> $LOGS_TMP && ERROR=1 fi fi fi fi echo "" >> $LOGS_TMP [ $ERROR -ne 0 ] && echo $ERROR > $ERROR_FILE done < $CONFIG_FILE fi grep 1 $ERROR_FILE > /dev/null GREP_ERROR=$? if [ $ERROR_GEN -ne 0 ]; then # envoi du mail echo "To: $MAIL_ADMIN" > $LOGS_MAIL echo "From: Server ICS SYNC Report <$MAIL_SENDER>" >> $LOGS_MAIL echo "Subject: [ERREUR TOTALE] Synchronisation fichiers ICS" - `date` >> $LOGS_MAIL cat $LOGS_TMP >> $LOGS_MAIL cat $LOGS_MAIL | /usr/sbin/sendmail -f $MAIL_ADMIN -t echo "Problème(s) important(s) rencontré(s) lors de l'éxécution de $0" >&2 cat $LOGS_TMP >> $LOGS_GEN rm $LOGS_TMP rm $LOGS_MAIL rm $ERROR_FILE exit 1 elif [ $GREP_ERROR -eq 0 ]; then # envoi du mail echo "To: $MAIL_ADMIN" > $LOGS_MAIL echo "From: Server ICS SYNC Report <$MAIL_SENDER>" >> $LOGS_MAIL echo "Subject: [ERREUR PARTIELLE] Synchronisation fichiers ICS" - `date` >> $LOGS_MAIL cat $LOGS_TMP >> $LOGS_MAIL cat $LOGS_MAIL | /usr/sbin/sendmail -f $MAIL_ADMIN -t echo "Problème(s) rencontré(s) lors de l'éxécution de $0" >&2 cat $LOGS_TMP >> $LOGS_GEN rm $LOGS_TMP rm $LOGS_MAIL rm $ERROR_FILE exit 1 elif [ $FORCEMAIL -eq 1 ]; then # envoi du mail echo "To: $MAIL_ADMIN" > $LOGS_MAIL echo "From: Server ICS SYNC Report <$MAIL_SENDER>" >> $LOGS_MAIL echo "Subject: Synchronisation fichiers ICS" - `date` >> $LOGS_MAIL cat $LOGS_TMP >> $LOGS_MAIL cat $LOGS_MAIL | /usr/sbin/sendmail -f $MAIL_ADMIN -t cat $LOGS_TMP >> $LOGS_GEN rm $LOGS_TMP rm $LOGS_MAIL rm $ERROR_FILE exit 0 fi cat $LOGS_TMP >> $LOGS_GEN rm $LOGS_TMP rm $LOGS_MAIL rm $ERROR_FILE exit 0
Une fois que vous avez entré les informations faites un petit [CTRL] + X
pour sortir, et n’oubliez pas de valider l’enregistrement par Yes
puis [Enter]
.
Puis rendez le script exécutable : sudo chmod 750 /usr/local/bin/kerio-ics-to-gcal/ics-sync.sh
.
Etape 6 : testez, testez, testez !
Faites un test depuis votre terminal : sudo /usr/local/bin/kerio-ics-to-gcal/ics-sync.sh -forcemail.
En passant l’option -forcemail
, vous allez recevoir, même si le script s’exécute correctement, un rapport par email. Cela vous permettra de vérifier que tout fonctionne correctement.
Si tout est OK, il ne vous reste plus qu’à programmer le lancement du script /usr/local/bin/kerio-ics-to-gcal/ics-sync.sh
depuis votre Crontab
(au via LaunchDaemon
sur OS X).
N’hésitez pas à me faire part de vos commentaires, retours ou améliorations !