OVH Cloud OVH Cloud

Script pour d=c3=a9coder les ent=c3=aates MIME

57 réponses
Avatar
Olivier Miakinen
Salut !

J'ai fait un script pour décoder les entêtes MIME selon le RFC 2047.
Je l'ai appelé decode2047 et je le joins à la fin de cet article.

Tests :

> om@kentia:~$ decode2047 "=?UTF-8?Q?Ceci_est_une_tentative_d'encoder_un_=5f_en_quoted-printab?= =?UTF-8?B?bGUgKHdhczogSMOpIGV0Yy4p?="
> Ceci est une tentative d'encoder un _ en quoted-printable (was: Hé etc.)
> om@kentia:~$ decode2047 "=?UTF-8?Q?Ceci_est_une_tentative_d'encoder_un_=5f_en_quoted-printab?= HELLO =?UTF-8?B?bGUgKHdhczogSMOpIGV0Yy4p?="
> Ceci est une tentative d'encoder un _ en quoted-printab HELLO le (was: Hé etc.)

Merci d'essayer pour voir si ça fonctionne aussi sur Mac (il faut les
commandes qprint et base64).

========================================================================
#!/bin/bash
# Script pour décoder un entête MIME

#
# Cette fonction vérifie que le paramètre est bien un encoded-word,
# puis elle le décode et le traduit en UTF-8.
#
# Si tout est OK, le résultat est dans $RESULT et la fonction retourne 0.
# Sinon, la fonction retourne 1.
#
decode_word()
{
# Un encoded-word doit être tout seul
if [ "$#" != "1" ]; then return 1; fi

# On vérifie que le paramètre est bien sous la forme :
# =?<charset>?<encoding>?<encoded>?=
# avec :
# <charset> : lettres, chiffres, underscores ou tirets
# <encoding> : B ou Q en majuscule ou minuscule
# <encoded> : ASCII imprimable sans espace ni point d'interrogation
if [ $(LANG=C expr "$1" : '=?[A-Za-z0-9_-]\+?[BbQq]?[!->@-~]\+?=$') = 0 ]
then
return 1;
fi

charset=$(printf "$1" | cut -f 2 -d '?')
encoding=$(printf "$1" | cut -f 3 -d '?')
encoded=$(printf "$1" | cut -f 4 -d '?')

case $encoding in
B | b)
decoded=$(printf "$encoded" | base64 -d 2>/dev/null)
if [ $? != 0 ]; then return 1; fi
;;
Q | q)
decoded=$(printf "$encoded" | tr "_" " " | qprint -d 2>/dev/null)
if [ $? != 0 ]; then return 1; fi
;;
*)
# Shouldn't occur
return 1
;;
esac

RESULT=$(printf "$decoded" | iconv -f $charset -t UTF-8)
return 0
}

FINAL_RESULT=""
PREV_RETCODE=

for word in $*
do
if decode_word "$word"
then
CURR_RETCODE=0
else
CURR_RETCODE=1
RESULT="$word"
fi

case "$PREV_RETCODE" in
0 )
# Previous string was an encoded-word.
# Add a space only if currect string is not.
if [ "$CURR_RETCODE" = "1" ]
then
RESULT=" ${RESULT}"
fi
;;
1 )
# Previous string was not an encoded-word.
# Always add a space.
RESULT=" ${RESULT}"
;;
* )
# There is no previous string.
# Never add a space.
;;
esac
PREV_RETCODE="$CURR_RETCODE"

FINAL_RESULT="${FINAL_RESULT}${RESULT}"
done

echo "$FINAL_RESULT"
========================================================================

Cordialement,
--
Olivier Miakinen

10 réponses

2 3 4 5 6
Avatar
M.V.
Nos posts viennent de se croiser !
Le 14 octobre 2019, Joseph-B a pris le temps d'écrire :
'/usr/local/bin/qprint' -d 2>/dev/null)

Ah oui... Je n'ai pas mis les '' autour du chemin ! Good !
cette fois tout marche COMME dans le Terminal, c'est à dire avec cette petite
bizarrerie que le "le" coupé de "printab…le" se trouve renvoyé après le HELLO

C'est ainsi qu'Olivier la rédigé !
Bonne soirée.
--
Michel VAUQUOIS - http://michelvauquois.fr
Avatar
josephb
M.V. proposa :
Tu peux tester avec un 3ème morceau en ISO-8859-1 cette fois !
Avec :
**********
set str to the clipboard
set decodeStr to decode(str)
set the clipboard to decodeStr
display alert decodeStr
on decode(str)
return do shell script "~/olivier.sh " & quoted form of str
end decode
**********
j'obtiens en copiant la séquence ci-dessus dans le pp :
"Ceci est une tentative d'encoder un _ en quoted-printab
HELLO le (was: Hé etc.) Re: Hé hé hé"

Pareil ici ; vraiment de la belle ouvrage !
--
J. B.
Avatar
Olivier Miakinen
Le 14/10/2019 19:58, Joseph-B a écrit :
Joseph-B wrote:
Ça a été bien plus vite que je ne pensais :
A priori, tu procèdes comme pour une commande shell classique, sauf que
tu dois indiquer le chemin complet vers le script d'Olivier.

do shell script "~/olivier.sh " & quoted form of str

Ou alors tu peux le mettre dans un répertoire qui est listé dans
la variable PATH.
Pour voir sa valeur actuelle :
echo $PATH
Moi je mets tous mes scripts persos dans un répertoire bin sous mon
home directory (c'est-à-dire ~/bin ou $HOME/bin), et j'ai ceci dans
mon .bashrc qui est lu au démarrage du shell bash :
# set PATH so it includes user's private bin if it exists
if [ -d "$HOME/bin" ] ; then
PATH="$HOME/bin:$PATH"
fi
Dans ce cas, pas besoin d'indiquer le chemin complet lors de l'appel.
[...]
Peut-être faudra-t-il donner le chemin complet de qprint qui n'est pas
une commande shell basique que le compilateur ApplesScript ne saura pas
trouver là où il est installé ?

encore exact,
si on introduit le chemin vers qprint dans le script d'Olivier
decoded=$(printf "$encoded" | tr "_" " " | '/usr/local/bin/qprint' -d 2>/dev/null)

Alors là, c'est pareil. Il faudrait dire à AppleScript d'aller regarder
aussi dans /usr/local/bin. Soit tu le fais au démarrage et ça suffit à
AppleScript, soit tu peux le rajouter au début de mon script :
PATH="/usr/local/bin:$PATH"
cette fois tout marche COMME dans le Terminal, c'est à dire avec cette petite
bizarrerie que le "le" coupé de "printab…le" se trouve renvoyé après le HELLO

C'était fait exprès, pour illustrer le fait que :
- si on enchaîne deux encoded words, ils sont collés sans espace
('printable' et pas 'printab le')
- mais s'il y a un texte non encodé (HELLO) des espaces sont ajoutées
('printab HELLO le' et pas 'printabHELLOle')
C'est dans la norme et c'est tout à fait logique puisque ça permet
d'avoir un très long encodage sans espace, tout en respectant la
règles des 76 caractères max par ligne. Et de ne pas avoir besoin de
rajouter une espace encodée quand on a par exemple « Re: =?...?= »)
Bonne soirée aussi,

De même.
--
Olivier Miakinen
Avatar
josephb
Bonsoir,
Olivier Miakinen <om+ apporta ses précisions :
do shell script "~/olivier.sh " & quoted form of str

Ou alors tu peux le mettre dans un répertoire qui est listé dans
la variable PATH.
Pour voir sa valeur actuelle :
echo $PATH

Oui, bonne idée, je regarde ce quelle contient d'utilisable
/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/bin
(aussi un chemin vers X11 et un autre vers WireShark, mais je sais
qu'AppleScript n'ira pas de lui même y regarder)
le seul répertoire "bin" qui ne soit pas verrouillé par le Système, même
en tant qu'admin, c'est /usr/local/bin
or AppleScript ne va pas y regarder non plus puisque qprint y est et
qu'on est obligé de lui donner explicitement le path (contrairement au
Terminal qui le voit)
Moi je mets tous mes scripts persos dans un répertoire bin sous mon
home directory (c'est-à-dire ~/bin ou $HOME/bin),

Pas de dossier ~/bin sur mon Mac (ce qui aurait été une bonne idée) et
je ne crois pas que le créer à la main lui donnera une quelconque valeur
aux yeux du Système du shell…
Bon je l'ai fait quand même et au prochain démarrage complet du Mac
j'irai voir à nouveau, mais pour l'instant il n'apparait pas dans le
$PATH même après relance du Terminal…
et j'ai ceci dans
mon .bashrc qui est lu au démarrage du shell bash :
# set PATH so it includes user's private bin if it exists
if [ -d "$HOME/bin" ] ; then
PATH="$HOME/bin:$PATH"
fi
Dans ce cas, pas besoin d'indiquer le chemin complet lors de l'appel.

decoded=$(printf "$encoded" | tr "_" " " | '/usr/local/bin/qprint' -d
2>/dev/null)
Alors là, c'est pareil. Il faudrait dire à AppleScript d'aller regarder
aussi dans /usr/local/bin.

je n'ai jamais lu dans la doc Applescript que ce soit possible. Ce qui
se passe dans son arrière-cuisine est assez mystérieux et verrouillé
d'avance. Applescript va explorer /bin et ses sous-dossiers, mais c'est
verrouillé pour nous. (ou je ne sais pas comment contourner le blocage)
Le seul moyen que je connaisse est d'inscrire le chemin en dur ou dans
une variable, et il sera pris en compte lors de la compilation du
script, ce n'est pas bien méchant
Soit tu le fais au démarrage et ça suffit à AppleScript,

Je ne sais pas faire et jamais lu que cela puisse se faire, mais bon, je
ne suis pas infaillible…
soit tu peux le rajouter au début de mon script :
PATH="/usr/local/bin:$PATH"

Ça ce serait possible en effet, et aurait l'avantage d'être dans les
déclarations plutôt que perdu au milieu des lignes de procédures.
cette fois tout marche COMME dans le Terminal, c'est à dire avec cette
petite bizarrerie que le "le" coupé de "printab…le" se trouve renvoyé
après le HELLO

C'était fait exprès, pour illustrer le fait que :
- si on enchaîne deux encoded words, ils sont collés sans espace
('printable' et pas 'printab le')
- mais s'il y a un texte non encodé (HELLO) des espaces sont ajoutées
('printab HELLO le' et pas 'printabHELLOle')

Je me disais bien que ce devait être voulu mais je ne comprenais pas le
pourquoi ;-)
C'est dans la norme et c'est tout à fait logique puisque ça permet
d'avoir un très long encodage sans espace, tout en respectant la
règles des 76 caractères max par ligne. Et de ne pas avoir besoin de
rajouter une espace encodée quand on a par exemple « Re: =?...?= »)

Aïe, encore une RFC que je n'ai pas lue ;-)
C'est surtout Michel qui aura l'utilité de cet outil, pour ses tests de
MacCafé, mais je me suis bien fait plaisir à trifouiller un peu dans les
arcanes d'Unix et du Terminal.
Cordialement
--
J. B.
Avatar
M.V.
Le 14 octobre 2019, le très estimable Joseph-B s'est exprimé en ces
termes :
C'est surtout Michel qui aura l'utilité de cet outil, pour ses tests de
MacCafé, mais je me suis bien fait plaisir à trifouiller un peu dans les
arcanes d'Unix et du Terminal.

Pas sûr d'en avoir besoin pour les tests de MacCafé mais moi aussi
j'ai pris bien du plaisir à participer à cet "agite-neurones"… J'ai
mis un "s" à "neurones" mais parfois j'ai des doutes en ce qui me
concerne ! ;-)
Bonne journée.
--
Michel VAUQUOIS - http://michelvauquois.fr
Avatar
josephb
Joseph-B wrote:
Pas de dossier ~/bin sur mon Mac (ce qui aurait été une bonne idée) et
je ne crois pas que le créer à la main lui donnera une quelconque valeur
aux yeux du Système du shell…
Bon je l'ai fait quand même et au prochain démarrage complet du Mac
j'irai voir à nouveau, mais pour l'instant il n'apparait pas dans le
$PATH même après relance du Terminal…

Confirmation après redémarrage du Mac : le Terminal ne met pas le
répertoire ~/bin que j'ai créé dans son $PATH, ni en bash, ni en zsh
censé être bien plus "smart" que bash.
On va en rester là, puisque le script d'Olivier marche à la sauce
AppleScript.
--
J. B.
Avatar
josephb
M.V. wrote:
J'ai > mis un "s" à "neurones" mais parfois j'ai des doutes en ce
qui me concerne ! ;-)

Alors comme dit la blague : "chic, à nous deux on en a trois !" ;-)
--
J. B.
Avatar
M.V.
Le 14 octobre 2019, le très estimable Olivier Miakinen s'est exprimé
en ces termes :
C'est dans la norme et c'est tout à fait logique puisque ça permet
d'avoir un très long encodage sans espace, tout en respectant la
règles des 76 caractères max par ligne.

C'est cette réponse de ta part que je cherchais...
Ton script va donc traiter deux "encoded words" mais, avec cette
règle des 76 caractères maximum par ligne, on se retrouve parfois
avec un sujet comportant plusieurs lignes comme celui-ci
<news: qnuof3$enp$ par exemple.
Comment règles-tu, toi, ce problème de transformation des 3 lignes en
une seule. Pour nous, en AppleScript, ça se fait aisément.
Bonne journée.
--
Michel VAUQUOIS - http://michelvauquois.fr
Avatar
Gilbert OLIVIER
Le 15 octobre 2019, M.V. a écrit:
Le 14 octobre 2019, le très estimable Olivier Miakinen s'est exprimé
en ces termes :
C'est dans la norme et c'est tout à fait logique puisque ça permet
d'avoir un très long encodage sans espace, tout en respectant la
règles des 76 caractères max par ligne.

C'est cette réponse de ta part que je cherchais...
Ton script va donc traiter deux "encoded words" mais, avec cette
règle des 76 caractères maximum par ligne, on se retrouve parfois
avec un sujet comportant plusieurs lignes comme celui-ci
<news: qnuof3$enp$ par exemple.
Comment règles-tu, toi, ce problème de transformation des 3 lignes en
une seule. Pour nous, en AppleScript, ça se fait aisément.

Dans MacCafé, pour l'encodage je fais appel à la fonction PHP
iconv_mime_encode dans laquelle tu passes entre autre comme paramètre
la longueur de ligne. Pour le décodage je reforme moi même une chaine
sans saut de ligne que je décode ensuite.
--
Gilbert
Avatar
Gilbert OLIVIER
Le 15 octobre 2019, M.V. a écrit:
Le 15 octobre 2019, le très estimable Gilbert OLIVIER s'est exprimé
en ces termes :
Pour le décodage je reforme moi même une chaine
sans saut de ligne que je décode ensuite.

Que veux-tu dire par "je reforme moi-même une chaine" ?

Le retour chariot marque la fin du champ sauf si la ligne suivante
commence par une espace. Donc quand je décompose le header en champ,
si la ligne suivante commence par une espace, je supprime le saut
ligne et l'espace (ça recolle tout le sujet en une seule chaine).
Mais ce que je voulais surtout savoir c'est si Olivier M. pouvait
intégrer dans son script ce passage de plusieurs lignes à une seule.

Sinon, ce sont mes premiers tests avec la portable comme tu peux le
voir dans le User-Agent, et pour une vieille machine très réactif
(bon, j'ai remplacé le HDD par un SSD et ça joue beaucoup).
--
Gilbert
2 3 4 5 6