Les fichiers MHTML décodés en Bash
Fichiers MHT sous Bash
J'ai été confronté à un fichier MHTML (d'extension .mht) et j'avais donc deux options pour consulter son contenu (32 fichiers...) : soit je faisais du copier-coller et du décodage (quoted-printable - RFC - et base64 - RFC) \"à la main\" et j'avais mon contenu en à peine 5 minutes, soit je faisais un script pour automatiser tout ça. Devinez ce que j'ai choisi...
�a me permet de parler d'une petite astuce de décodage de contenu en base64 que j'avais trouvé je ne sais plus trop où :
openssl base64 -d -in inputFile -out outputFile openssl base64 -d < inputFile > outputFile
Pour faire court, à partir du fichier .mht, on le découpe (avec csplit), on traite les parties suivant qui sont encodées en base64 (fichiers binaires) ou quoted-printable (pour les autres pages web dans le cas d'un frameset). Et hop !
#!/bin/bash
#Explode a .mht archive into its original files.
#Syntax : explodemht MHTFile DestFolder
#Needed : php (pour le rawurldecode), openssl (pour le base64 decode) et "recode" pour le Quoted-Printable
[[ ${#} -lt 2 ]] && echo "Pas assez d'arguments : le fichier MHT et le dossier de destination" && exit 1;
MHTFile=${1}
[[ ! -f $MHTFile ]] && echo "Le fichier <$MHTFile> n'existe pas." && exit 2;
mainFolder=${2}
[[ ! -d $mainFolder ]] && mkdir "$mainFolder";
#Passe 0 : on fait le split du fichier .mht
SplitPrefix="mht_exploding_"
csplit -f $SplitPrefix "$MHTFile" /^\-\-\-\-\-\-=_NextPart/ {*} > /dev/null
#Première passe : on extrait tous les fichiers de l'archive MIME et on les décode correctement
echo "On crée les fichiers :"
j=0
NewNames=()
OriginalName=()
Encodings=()
for item in $SplitPrefix*; do
FileName=`cat $item| grep -m 1 "Content-Location:" | awk '{print $2}' | sed 's/\r//g'`
OriginalNames[$j]=$FileName
FileName=`php -q -r 'echo (isset($_SERVER["argv"][1]) ? rawurldecode($_SERVER["argv"][1]) : "");' ${FileName}`
FileName=`echo ${FileName} | sed 's/\\\/\//g'`
FileName=`basename "${FileName}" | sed 's/\r//g'`
Encoding=`cat $item| grep -m 1 "Content-Transfer-Encoding:" | sed 's/\r//g' | awk '{print $2}'`
Encodings[$j]=$Encoding
FirstEmptyLine=`cat $item | sed 's/\r//g' | grep -m 1 -n '^$' | awk 'BEGIN{FS=":"}{print $1}'`
((FirstEmptyLine++))
if [[ ${#FileName} -ne 0 ]]; then
echo "Fichier $j : ${FileName} - ($Encoding)"
NewNames[$j]=${FileName}
[[ ${Encoding} == "base64" ]] && sed -n $FirstEmptyLine',$p' $item | openssl base64 -d -out "$mainFolder/${FileName}";
if [[ ${Encoding} == "quoted-printable" ]]; then
sed -n $FirstEmptyLine',$p' $item | recode windows-1252/CRLF.. | recode /qp.. > $mainFolder/${FileName}
fi
fi
((j++))
done
#Deuxième passe : on fixe les liens HTML qui peuvent être invalides
i=0
while [[ $i -lt $j ]]; do
if [[ ${Encodings[$i]} == "quoted-printable" ]]; then
k=0
echo "On traite les liens du fichier ${NewNames[$i]}."
while [[ $k -lt $j ]]; do
[[ ${#NewNames[$k]} == 0 ]] && ((k++)) && continue;
OriginalName=`echo -n ${OriginalNames[$k]} | sed 's@\\\@\\\\@g;s@&@&@g;s@%26@&@g'`
cat $mainFolder/${NewNames[$i]} | sed 's@'$OriginalName'@'${NewNames[$k]}'@g;s@'${OriginalNames[$k]}'@'${NewNames[$k]}'@g' > tempfile.tmp
cp tempfile.tmp $mainFolder/${NewNames[$i]}
((k++))
done
fi
((i++))
done
#On nettoie
rm -f tempfile.tmp
rm -f $SplitPrefix*
En fait c'est énervant à écrire. Parce que je suis trop bête et que je n'ai pas trouvé d'équivalent à rawurldecode sous Bash. Parce que le code n'est pas beau. Du tout. Et parce que ça marche, rageant...
Il faut donc inclure un programme C qui implémente le rawurldecode et coder tout ça un peu plus proprement...
