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...
