Twitter iPhone pliant OnePlus 11 PS5 Disney+ Orange Livebox Windows 11

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

1 2 3 4 5
Avatar
M.V.
Le 14 octobre 2019, Olivier Miakinen a pris le temps d'écrire :
Et est-ce qu'on l'appelle bien avec « base64 -d » ?

Non ! C'est « base64 -D » !!!
Je me suis déjà fait piéger avant-hier alors je m'en souviens !
Je fais la modif dans le script et je reviens.
Bonne soirée.
--
Michel VAUQUOIS - http://michelvauquois.fr
Avatar
M.V.
Le 14 octobre 2019, Olivier Miakinen a pris le temps d'écrire :
C'est le décodage par base64 qui n'a pas fonctionné. Tu as bien installé
le programme ? Et est-ce qu'on l'appelle bien avec « base64 -d » ?

Bingo ! C'était bien la minuscule à la place de la majuscule qui mettait la pagaille.
J'ai à nouveau viré le "set -x" et j'obtiens :
**********
~/olivier.sh "=?UTF-8?Q?Ceci_est_une_tentative_d'encoder_un___en_quoted-printab?= =?UTF-8?B?bGUgKHdhczogSMOpIGV0Yy4p?="
Ceci est une tentative d'encoder un _ en quoted-printable (was: Hé etc.)
**********
et pour la 2ème séquence :
**********
~/olivier.sh "=?UTF-8?Q?Ceci_est_une_tentative_d'encoder_un___en_quoted-printab?= HELLO =?UTF-8?B?bGUgKHdhczogSMOpIGV0Yy4p?="
Ceci est une tentative d'encoder un _ en quoted-printab HELLO le (was: Hé etc.)
**********
Bravissimo !!!
Bonne soirée.
--
Michel VAUQUOIS - http://michelvauquois.fr
Avatar
josephb
Olivier Miakinen <om+ wrote:
Merci Olivier pour tes réponses ici qui me satisfont pleinement et ne
t'embête pas pour ma demande en courriel privé
- utiliser un autre shell, peut-être /bin/zsh, et changer la première
ligne du script en #!/bin/zsh.

Comme ce changement effectué ne donnait le même message d'erreur alors que
tous les autres commandes ou scripts ne posaient pas de problème, je me suis
soudain rappelé avoir connu un jour des erreurs longtemps incompréhensibles
de refus du Terminal sur autre script.
La cause était et c'est aussi le cas présent, que je viens donc de
solutionner, que ce conn**d de TextEdit (le traitement de texte par défaut
d'OS X), mélange joyeusement les CR et LF quand on le bascule en texte brut
alors qu'il était en RTF --> Fins de ligne incompréhensibles pour le
Terminal qui ne sait même plus à quelle erreur se vouer :-/
Manque de vigilance de ma part !
J'ai recréé le script avec un outil plus sérieux, et maintenant il est vu
comme valide par le Terminal, mais même en zsh* il ne marche que comme chez
M. V., se contentant de retourner en résultat la chaîne entrée intacte.
*sur le tout dernier opus d'OS X, Catalina, c'est maintenant zsh le shell
par défaut, mais on peut compter sur Apple pour le remanier à sa sauce…
--
J. B.
Avatar
M.V.
Le 14 octobre 2019, Joseph-B a pris le temps d'écrire :
J'ai recréé le script avec un outil plus sérieux

Le mien est fait avec TextEdit ! ;-)
Il est là :
<https://www.dropbox.com/s/jyu83vl9g5eg735/olivier.sh?dl=0>
Peut-être faudra-t-il vérifier les droits ? Je n'en sais rien à vrai
dire.
En tout cas, après toutes ces péripéties, il marche excellemment.
Faudra que tu me dises si c'est possible d'-intégrer ce genre de
script dans un script AS car ça, tu ne m'as jamais montré !
Bonne soirée.
--
Michel VAUQUOIS - http://michelvauquois.fr
Avatar
josephb
M.V. wrote:
Bravissimo !!!

Bon, j'ai apporté les modifs aux regex et le -D de base64, mais ça ne
donne rien chez moi… J'ai ENCORE dû foirer quelque chose encore !
Peux-tu poster l'intégralité du script "qui marche" que j'en refasse un
.sh et le teste à mon tour ?
Heuuuu ?
tu fais ça comment :
Avec le détail, ça donne ça :
**********
~/olivier.sh "=?UTF-8?B?bGUgKHdhczogSMOpIGV0Yy4p?="
+ '[' 1 '!=' 1 ']'
++ LANG=C

Cordialement
Merci
--
J. B.
Avatar
M.V.
Le 14 octobre 2019, Joseph-B a pris le temps d'écrire :
Peux-tu poster l'intégralité du script "qui marche" que j'en refasse un
..sh et le teste à mon tour ?

Je viens de te l'envoyer sinon, ça donne ça :
**********
#!/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
# set -x
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 2>/dev/null)
return $?
}
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"
**********
Heuuuu ?
tu fais ça comment :
Avec le détail, ça donne ça :


Tu repères dans le script la ligne "#set -x" qui se trouve là:
**********
decode_word()
{
# Un encoded-word doit être tout seul
# set -x
**********
et tu vires le "# " qui l'annihile.
Ça va donner :
**********
decode_word()
{
# Un encoded-word doit être tout seul
set -x
**********
Bonne soirée.
--
Michel VAUQUOIS - http://michelvauquois.fr
Avatar
josephb
M.V. wrote:
Le mien est fait avec TextEdit ! ;-)

TextEdit merdoie avec les CR et LF quand la saisie (ou collage) a été
faite alors que la fenêtre est en mode RTF et que l'on bascule en texte
brut.
Deuxième fois que je me fais piéger. Du coup j'ai pris BBEdit
Il est là :
<https://www.dropbox.com/s/jyu83vl9g5eg735/olivier.sh?dl=0>

OKèèèè, ça répond à ma demande, je vais tester et pour ce qui est de
Faudra que tu me dises si c'est possible d'-intégrer ce genre de
script dans un script AS

A priori, tu procèdes comme pour une commande shell classique, sauf que
tu dois indiquer le chemin complet vers le script d'Olivier.
Base64 appelé par le script va bien passer mais je crains qu'on ait un
souci au niveau de qprint.
je n'ai aucune idée si le compilateur AppleScript va vouloir précompiler
le tout ou s'il va laisser s'exécuter les appels au cas par cas.
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é ?
--
J. B.
Avatar
josephb
M.V. wrote:
Je viens de te l'envoyer sinon, ça donne ça :

Je l'ai pris sur ta dropbox, remis les autorisations et maintenant ça marche
effectivement à la perfection,
recombinaison des fragments qp et base64 qui avaient sucissonné le sujet !
Je suis soufflé du résultat :-D
Bravo Olivier !
Et merci à toi
Plus tard j'essaierai de voir l'incorporation avec Applescript, là je dois
m'arrêter…
Cordialement
--
J. B.
Avatar
josephb
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
où str est la variable contenant l'entête mixte B64 et QP
Base64 appelé par le script va bien passer

exact !
la partie Base64 a été décodée
mais je crains qu'on ait un souci au niveau de qprint.

en effet la partie QP ne décode pas
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)
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
< Ceci est une tentative d'encoder un _ en quoted-printab HELLO le (was: Hé etc.)>
Bonne soirée aussi,
--
J. B.
Avatar
M.V.
Le 14 octobre 2019, Joseph-B a pris le temps d'écrire :
Plus tard j'essaierai de voir l'incorporation avec Applescript

Je viens d'incorporer le script dans un script AS avec simplement :
**********
set str to "HELLO =?UTF-8?B?bGUgKHdhczogSMOpIGV0Yy4p?="
do shell script "~/olivier.sh " & quoted form of str
**********
Ça marche et j'obtiens bien :
"HELLO le (was: Hé etc.)"
mais avec un UTF-8 Q, ça foire et je ne sais pas indiquer dans le script d'Olivier le chemin de
qprint.
J'avais simplement remplacé
*****
decoded=$(printf "$encoded" | tr "_" " " | qprint -d 2>/dev/null)
*****
par
*****
decoded=$(printf "$encoded" | tr "_" " " | usr/local/bin/qprint -d 2>/dev/null)
*****
mais c'est raté (même dans le Terminal, le script ne fonctionne plus avec ce changement).
Bonne soirée.
--
Michel VAUQUOIS - http://michelvauquois.fr
1 2 3 4 5