OVH Cloud OVH Cloud

Nouveau script pour d=c3=a9coder les ent=c3=aates MIME

35 réponses
Avatar
Olivier Miakinen
Bonjour,

J'ai fait une nouvelle version de mon script. Au lieu de prendre en
paramètre une ou plusieurs chaînes à décoder, il prend en paramètre
un ou plusieurs noms de fichiers contenant les entêtes complets.
On peut aussi lui faire lire les données sur stdin si on ne met pas
de paramètre, ou qu'on met « - » à la place d'un nom de fichier.

Par exemple, si on saisit :

decode_headers <<POTIRON
Message-ID: <c5a9-1@part.org>
From: Arvo =?UTF-8?Q?P=C3=A4rt?= <arvo@part.org>
To: =?Latin1?Q?Fr=E9d=E9ric_Chopin?= <fred@chopin.org>,
=?Latin2?Q?Anton=EDn_Dvo=F8=E1k?= <anton@dvorak.org>
References: <A65R-4d@chopin.org> <c5a7-3@part.org>
<A72Q-5a@chopin.org>
In-Reply-To: <A72Q-5a@chopin.org>
Subject: Re: Going to =?Shift-JIS?B?k4yLngo=?= (Tokyo) =?UTF-8?B?zpEK?=
=?UTF-8?B?zrjOrs69zrEK?= (Athens) and =?ISO-8859-5?Q?=BC=DE=E1=DA?=
=?ISO-8859-5?Q?=D2=D0?= (Moscow)
POTIRON

On obtiendra :

Message-ID: <c5a9-1@part.org>
From: Arvo Pärt <arvo@part.org>
To: Frédéric Chopin <fred@chopin.org>, Antonín Dvořák <anton@dvorak.org>
References: <A65R-4d@chopin.org> <c5a7-3@part.org> <A72Q-5a@chopin.org>
In-Reply-To: <A72Q-5a@chopin.org>
Subject: Re: Going to 東京 (Tokyo) Αθήνα (Athens) and Москва (Moscow)

(Note : le mot POTIRON n'a rien de spécial, c'est juste pour aider
OuiOui à améliorer son karma)


Voici le script. Attention, pour l'adapter au Mac il faudra modifier les
variables CUT, DECODE_QP, DECODE_B64, TR et ICONV définies vers le début
du fichier.

========================================================================
#!/bin/bash
####################################################################
# Name:
# decode_headers
#
# Description:
# Script used for decoding RFC 2047 MIME encoded headers.
#
# Example:
# decode_headers <<POTIRON
# Message-ID: <c5a9-1@part.org>
# From: Arvo =?UTF-8?Q?P=C3=A4rt?= <arvo@part.org>
# To: =?Latin1?Q?Fr=E9d=E9ric_Chopin?= <fred@chopin.org>,
# =?Latin2?Q?Anton=EDn_Dvo=F8=E1k?= <anton@dvorak.org>
# References: <A65R-4d@chopin.org> <c5a7-3@part.org>
# <A72Q-5a@chopin.org>
# In-Reply-To: <A72Q-5a@chopin.org>
# Subject: Re: Going to =?Shift-JIS?B?k4yLngo=?= (Tokyo) =?UTF-8?B?zpEK?=
# =?UTF-8?B?zrjOrs69zrEK?= (Athens) and =?ISO-8859-5?Q?=BC=DE=E1=DA?=
# =?ISO-8859-5?Q?=D2=D0?= (Moscow)
# POTIRON
# ->
# Message-ID: <c5a9-1@part.org>
# From: Arvo Pärt <arvo@part.org>
# To: Frédéric Chopin <fred@chopin.org>, Antonín Dvořák <anton@dvorak.org>
# References: <A65R-4d@chopin.org> <c5a7-3@part.org> <A72Q-5a@chopin.org>
# In-Reply-To: <A72Q-5a@chopin.org>
# Subject: Re: Going to 東京 (Tokyo) Αθήνα (Athens) and Москва (Moscow)
#
# Known bugs:
# Can't handle encoded-words which are not clearly separated
# from non-blank characters, e.g. in comments: (=?...?.?...?=)
####################################################################

#
# The following constants should be adapted for your system.
# For example, the executable base64 could be at /usr/local/bin instead
# of /usr/bin, and it could require parameter -D instead of -d.
#
CUT="/usr/bin/cut"
DECODE_QP="/usr/bin/qprint -d"
DECODE_B64="/usr/bin/base64 -d"
TR="/usr/bin/tr"
ICONV="/usr/bin/iconv"

#
# This script uses the following global variables
# VARY
# used when a function has to return a string and not only a number
# DECODED_LINE
# The current state of a header being currently decoded
# STATUS
# Has three possible values:
# - "none" at the beginning of a new header
# - "decoded-word" after a correctly decoded MIME part
# - "normal" after any other string
#
VARY=""
DECODED_LINE=""
STATUS="none"

#
# Function: usage
#
usage()
{
printf "Usage: %s [OPTION...] [FILE...]\n" $0
printf "Decode headers from given files for RFC 2047 MIME encodings.\n"
printf "\n"
printf "With no FILE, or when FILE is -, read standard input.\n"
printf "\n"
printf " -h, --help Give this help list\n"
exit 1
}

#
# Function: decode_word
#
# Description:
# Check that the parameter is an encoded word, then decode it and
# convert it to UTF-8.
#
# Parameter:
# A single (possibly MIME-encoded) word.
#
# Return value:
# If decoding is ok, set the result into VARY and return 0
# Otherwise return 1
#
decode_word()
{
word="$*"
###################################################################
# An encoded word contains only ASCII characters in range from
# '!' (Ascii value 0x21) to '~' (Ascii value 0x7e). This excludes
# in particular the SPACE (Ascii 0x20) and the TAB (Ascii 0x09).
#
# More specifically, it consists of five parts separated by
# question marks '?'
# 1. A character "="
# 2. The charset, e.g. "UTF-8" or "ISO-8859-1"
# 3. The encoding, B or Q in upper or lower case
# 4. The encoded text
# 5. A character "="
###################################################################

# Check that:
# - there is no character outside range from '!' to '~'
# - the 1st part is a "="
# - the 5th part is a "=" and it is the end of the string
if [ $(LANG=C expr "_$word" : '_=?[!-~]*=$') = 0 ]; then return 1; fi
end=$(printf "$word" | $CUT -f 5- -d '?')
if [ "$end" != "=" ]; then return 1; fi

# Extract charset, encoding, and encoded text
charset=$(printf "$word" | $CUT -f 2 -d '?')
encoding=$(printf "$word" | $CUT -f 3 -d '?')
encoded=$(printf "$word" | $CUT -f 4 -d '?')

case $encoding in
B | b)
decoded=$(printf "$encoded" | $DECODE_B64 2>/dev/null)
if [ $? != 0 ]; then return 1; fi
;;
Q | q)
decoded=$(printf "$encoded" | $TR "_" " " | $DECODE_QP 2>/dev/null)
if [ $? != 0 ]; then return 1; fi
;;
*)
return 1
;;
esac

VARY=$(printf "$decoded" | $ICONV -f $charset -t UTF-8 2>/dev/null)
return $?
}

#
# Function: add_word
#
# Description:
# Try to decode a new word, and update DECODED_LINE and STATUS
# depending on the result and the previous STATUS.
#
# Parameter:
# A single (possibly MIME-encoded) word.
#
# Return value:
# None
#
# Side effects:
# Change DECODED_LINE and STATUS
#
add_word()
{
word="$*"
if decode_word "$word"; then
if [ "$STATUS" = "normal" ]; then
DECODED_LINE="${DECODED_LINE} "
fi
DECODED_LINE="${DECODED_LINE}${VARY}"
STATUS="decoded-word"
else
if [ "$STATUS" != "none" ]; then
DECODED_LINE="${DECODED_LINE} "
fi
DECODED_LINE="${DECODED_LINE}${word}"
STATUS="normal"
fi
}

#
# Function: flush_line
#
# Description:
# Before beginning to manage a new header, or just before ending
# the script, print the pending DECODED_LINE if any.
#
# Parameter:
# None
#
# Return value:
# None
#
# Side effects:
# Print things to stdout
# Change DECODED_LINE and STATUS
#
flush_line()
{
if [ -n "${DECODED_LINE}" ]; then
printf "%s\n" "${DECODED_LINE}"
DECODED_LINE=""
STATUS="none"
fi
}

#
# Function: manage_line
#
# Description:
# Manage a new line, which can be either the beginning or the
# continuation of a mail/news header.
# This function prints the previous line if this is a new one,
# then it adds successive parts to the new DECODED_LINE, while
# updating STATUS as needed.
#
# Parameter:
# An input
line.========================================================================

#
# Return value:
# None
#
# Side effects:
# Print things to stdout
# Change DECODED_LINE and STATUS
#
manage_line()
{
line="$*"

# Is it a continuation line?
if [ $(LANG=C expr "$line" : "[ \t]") = 0 ]; then
# No: new header
flush_line
fi

for word in $line; do
add_word "$word"
done
}

#
# Function: manage_file
#
# Description:
# Call manage_line for each line in a given file
#
# Parameter:
# A file name, or "-" for stdin
#
# Return value:
# None
#
# Side effects:
# Same as manage_line
#
manage_file()
{
file=${1--} # POSIX-compliant; ${1:--} can be used either.
while IFS= read -r line; do
manage_line "$line"
done < <(cat -- "$file")
}

#
# Parse arguments for -h or --help
#
for i in "$@"; do
case $i in
-h | --help)
usage
;;
-)
;;
-*)
printf "Unknown argument '%s'\n" "$i"
usage
;;
esac
done

#
# Main loop.
# Call manage_file for each filename in parameters,
# then print the last pending DECODED_LINE if any.
#
for file in "$@"; do
manage_file "$file"
done
flush_line

exit 0
========================================================================

--
Olivier Miakinen

10 réponses

1 2 3 4
Avatar
Olivier Miakinen
Le 17/10/2019 à 16:49, M.V. a écrit :
Ainsi parlait Olivier Miakinen le 17 octobre 2019 :
Oui, c'est ce que j'écrivais dans « known bugs », et c'est pour ça
que je posais la question pour le tien.
<cit. news:qo8al1$12kl$

Ça c'est le nouveau script

Oui, mais c'est un bug qui existe dans les deux.
(que je n'arrive pas à faire fonctionner).

À cause d'une ligne de commentaires ? Ben vire là !
Moi je parlais de celui de dimanche tard dans la nuit quon a fini par
faire fonctionner sur le Mac.

Tu peux aussi recopier le début du script que tu as réussi à faire
fonctionner, au début de ce nouveau script. Il n'y a pas de raison
que ça plante sur une ligne de commentaire.
--
Olivier Miakinen
Avatar
josephb
Olivier Miakinen <om+ wrote:
Ok. Ça n'a même aucune chance d'arriver puisque le caractère £ n'est
pas de l'ASCII, et est donc interdit dans les entêtes. ;-)

alors, une substitution avec sed, à la manière de ce que fait Michel en
Applescript, serait-elle possible ?
--
J. B.
Avatar
M.V.
Olivier Miakinen a suggéré en date du 17 octobre 2019 :
(que je n'arrive pas à faire fonctionner).

À cause d'une ligne de commentaires ? Ben vire là !

Pardon mais je ne maîtrise absolument pas ce genre de script !
J'ai viré 2 lignes de commentaires et maintenant j'ai :
#: bad interpreter: No such file or directory
Je ne suis pas sûr de savoir ce que je dois entrer dans le Terminal !
Je dois mettre ton exemple entre guillemets parce que mon Terminal
n'accepte pas les retours chariot comme tu l'as présenté dans ton 1er
message ?
Je vais laisser, s'il est intéressé, Joseph-B qui est beaucoup plus
calé que moi pour la suite car là, je patauge ! Désolé.
Bonne soirée.
--
Michel VAUQUOIS - http://michelvauquois.fr
Avatar
Olivier Miakinen
Le 17/10/2019 à 18:28, M.V. a écrit :
(que je n'arrive pas à faire fonctionner).

À cause d'une ligne de commentaires ? Ben vire là !

Pardon mais je ne maîtrise absolument pas ce genre de script !

Pourtant tu as su faire fonctionner le script précédent, ça
devrait être du même style. Tu as copié le tout dans un fichier
que tu as appelé decode_headers ou decode_headers.sh et à qui
tu as donné les droits d'exécution ? C'est ce fichier que tu
appelles depuis AppleScript, par '/le_chemin/decode_headers'
ou par '/bin/bash /le_chemin/decode_headers' ? Et si les
entêtes à décoder sont dans un fichier tu passes le chemin
complet vers ce fichier en paramètre de decode_headers ?
J'ai viré 2 lignes de commentaires et maintenant j'ai :
#: bad interpreter: No such file or directory

Compare le début du fichier contenant le script bash qui fonctionne
avec le début du fichier contenant le script bash qui ne fonctionne
pas. Tu devrais forcément voir une différence.
--
Olivier Miakinen
Avatar
M.V.
Joseph-B a suggéré en date du 17 octobre 2019 :
le script est appelé "Olivier2.sh"
une fois les modifs pour Mac apporté, et dans le Terminal
j'ai l'erreur
/usr/local/bin/Olivier2.sh: line 210: command not found

Moi j'ai seulement et toujours :
*****
MV$ /usr/local/bin/olivier2.sh
#: bad interpreter: No such file or directory
*****
Fait chier !
Bonne soirée.
--
Michel VAUQUOIS - http://michelvauquois.fr
Avatar
M.V.
Joseph-B a suggéré en date du 17 octobre 2019 :

Tu peux faire un copier/coller du script d'Olivier tel que tu l'as
chez toi pour que je regarde pourquoi ça ne fonctionne pas du tout
chez moi ?
Bonne soirée.
--
Michel VAUQUOIS - http://michelvauquois.fr
Avatar
Olivier Miakinen
Le 17/10/2019 à 20:18, M.V. a écrit :
Moi j'ai seulement et toujours :
*****
MV$ /usr/local/bin/olivier2.sh
#: bad interpreter: No such file or directory
*****

Que donnent...
*****
MV$ bash /usr/local/bin/olivier2.sh
*****
et
*****
MV$ head /usr/local/bin/olivier2.sh
*****
?
--
Olivier Miakinen
Avatar
M.V.
Olivier Miakinen a suggéré en date du 17 octobre 2019 :
Que donnent...
*****
MV$ bash /usr/local/bin/olivier2.sh
*****

Rien ! Rien de rien !
Le Terminal ne râle pas, ne saute pas de joie… Un grand mutisme frisé !
et
*****
MV$ head /usr/local/bin/olivier2.sh
*****

Là, il est un peu plus bavard :
*****
exit 0MacBook-Air-MV:bin MV$ DECODED_LINE if any.,sed either.==========v/null)
*****
--
Michel VAUQUOIS - http://michelvauquois.fr
Avatar
Manfred La Cassagnère
Le 17 octobre 2019, Olivier Miakinen a demandé:
Histoire que je me couche moins bête (et que je sache répondre aux
questions de Michel), tu aurais une doc AppleScript à me conseiller ?
http://trad.applescript.free.fr/generalas.html

Hth
--
Manfred
Middle Of Nowhere
iMac Intel Core 2 Duo, early 2009, OS X 10.11.6
"I would trade all my technology for an afternoon with Socrates."(S.J.)
Avatar
josephb
Olivier Miakinen <om+ wrote:
Histoire que je me couche moins bête (et que je sache répondre aux
questions de Michel), tu aurais une doc AppleScript à me conseiller ?

Je n'ai jamais eu de "bouquin" écrit par un ténor d'Applescript, ou de
site de tutoriels.
J'ai appris sur le tas pour l'élémentaire et beaucoup par imitation de
scripts existants pour des choses plus pointues.
Toute la doc officielle en ligne dont je me sers,
C'est relativement laconique et avare en exemples autres que très
élémentaires ; je ne crois pas que ça t'apprendra grand chose d'utile,
en tous cas pour cet exercice
<https://developer.apple.com/library/archive/documentation/AppleScript/Conceptual/AppleScriptLangGuide/Index/index_of_book.html#C>
Tu y trouveras le chapitre congru consacré au "do shell script"
mais il existe aussi une note technique plus détaillée
<https://developer.apple.com/library/archive/technotes/tn2065/_index.htmlW>
--
J. B.
1 2 3 4