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 nomducomptelogin monadresse@gcalendar.compassword 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_2pour 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_FILEcontiendra 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_FILEScontiendra l’emplacement des fichiers ICS téléchargés en local, ce dossier devant être joignable en HTTP ;$WEB_PATH_ICScontiendra l’URL permettant de joindre sur le web le dossier$PATH_FILES;$LOGS_GENcontiendra l’emplacement des journaux du script, par défaut ici/var/log/ics_sync.log$MAIL_ADMINcontiendra l’adresse email pour les rapports d’exécution ;$MAIL_SENDERcontiendra 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 !