Lire les .msf (Thunderbird)
Les fichier msf
(mail summary file) sont encodé en mork (https://en.wikipedia.org/wiki/Mork_(file_format)).
Usage dans Thunderbird
Dans Thunderbird, le but de ces fichiers est de présenter un index des courriels présents dans les boites mail.
- Si ce fichier n'existe pas, il est créé en relisant l'ensemble du dossier courant,
- s'il est corrompu ou que la création échoue, le message
"Impossible d'ouvrir le fichier de résumé pour <DOSSIER> sur <COMPTE>. Il se peut qu'il y ait une erreur sur le disque ou que le chemin complet soit trop long."
est affiché. - il peut ne pas être complètement à jour, dans ce cas l'affichage de la boite courriel ne correspond pas à aux fichiers réellement présents (exemple: des fichiers marqués supprimés sont encore visibles, ou le contraire, des fichiers sensés être là ne sont pas visibles).
- Lorsqu'on fait un clic droit sur un dossier et qu'on clic sur
propriétés
puis surréparer le dossier
on force la réécriture de ce fichier d'index.msf
Détail d'implémentation (copie du code de Thunderbird sur github):
- peut échouer sur:
- obtention d'un objet
msgDBService
- si échoué, envoyer une popup avec le code d'erreur
errorGettingDB
(Impossible d'ouvrir le fichier de résumé pour <DOSSIER> sur <COMPTE>. Il se peut qu'il y ait une erreur sur le disque ou que le chemin complet soit trop long.)
cf doc: https://thunderbird-interfaces.readthedocs.io/en/latest/nsIMsgDBService.html#methods
Lire le contenu d'un fichier .msf
D'abord installer le module perl Mozilla::Mork (cf: https://metacpan.org/release/KRIPT/Mozilla-Mork-0.01/view/lib/Mozilla/Mork.pm)
perl -MCPAN -e shell install Mozilla::Mork
Puis créer le fichier perl suivant read_msf.pl
avec ce contenu (inspiré du site ci dessus):
#! /usr/bin/env perl use Mozilla::Mork; use Data::Dumper; $file = $ARGV[0]; unless ($file) { die "Usage: $0 <filename>\n"; } #get a reference to an array of hash's my $MorkDetails = Mozilla::Mork->new($file); my $results = $MorkDetails->ReturnReferenceStructure(); print Dumper($results);
Donner les droits d'execution
chmod +x read_msf.pl
Usage:
./read_msf.pl <chemin_vers_fichier_msf>
Note: à la première installation, le shell CPAN
installe des variables d'environnement dans ~/.bashrc
pensez à recharger le fichier avant de lancer le script.
Exemple de sortie
Exemple un dossier ne contenant que 2 courriels: “ceci est un test” (lu) et “test non lu” (non lu):
Le .msf original:
// <!-- <mdb:mork:z v="1.4"/> --> < <(a=c)> // (f=iso-8859-1) (B8=imapFlags)(B9=highestRecordedUID) (BA=ns:msg:db:row:scope:pending:all)(BB=ns:msg:db:table:kind:pending) (BC=dateReceived)(BD=ProtoThreadFlags) (BE=dobayes.mailnews@mozilla.org#junk.empty) (BF=dobayes.mailnews@mozilla.org#junk)(C0=junkscore)(C1=keywords) (C2=imageSize)(C3=recipient_names)(C4=folderName)(C5=storeToken) (C6=junkscoreorigin)(C7=junkpercent)(C8=preview)(C9=pseudoHdr) (CA=ns:msg:db:row:scope:ops:all)(CB=ns:msg:db:table:kind:ops)(CC=op) (CD=msgKey)(CE=opFlags)(CF=newFlags)(D0=srcFolderURI)(D1=srcMsgKey) (80=ns:msg:db:row:scope:msgs:all)(81=subject)(82=sender)(83=message-id) (84=references)(85=recipients)(86=date)(87=size)(88=flags)(89=priority) (8A=label)(8B=numLines)(8C=ccList)(8D=bccList)(8E=msgThreadId) (8F=threadId)(90=threadFlags)(91=threadNewestMsgDate)(92=children) (93=unreadChildren)(94=threadSubject)(95=msgCharSet) (96=ns:msg:db:table:kind:msgs)(97=ns:msg:db:table:kind:thread) (98=ns:msg:db:table:kind:allthreads) (99=ns:msg:db:row:scope:threads:all)(9A=threadParent)(9B=threadRoot) (9C=msgOffset)(9D=offlineMsgSize) (9E=ns:msg:db:row:scope:dbfolderinfo:all) (9F=ns:msg:db:table:kind:dbfolderinfo)(A0=numMsgs)(A1=numNewMsgs) (A2=folderSize)(A3=expungedBytes)(A4=folderDate)(A5=highWaterKey) (A6=mailboxName)(A7=UIDValidity)(A8=totPendingMsgs) (A9=unreadPendingMsgs)(AA=expiredMark)(AB=version)(AC=forceReparse) (AD=fixedBadRefThreading)(AE=onlineName)(AF=MRUTime)(B0=MRMTime) (B1=sortType)(B2=sortOrder)(B3=viewFlags)(B4=viewType)(B5=sortColumns) (B6=columnStates)(B7=highestModSeq)> <(80=1)(94=fffffffe)(91=647729c3)(81=0)> [1:m(^9B=1)(^8F^94)(^91^91)(^90=0)(^92=1)(^93=1)] <(A8=2)>[2:m(^9B=2)(^8F=2)(^91=0)(^90=0)(^92=0)(^93=0)] <(97=80)(8D=John Doe <john.doe@cliss21.org>)(8E =John DOE <john.doe@cliss21.org>)(8F=ceci est un test) (90=cc738647-4cb6-6942-8fc3-308174672f77@cliss21.org)(92=82f)(93 =ffffffff)(95=993|John DOE)(86=882)(96=2178)(98=3a)(99=plugin) (9A=13)(9B=nonjunk)> {1:^80 {(k^96:c)(s=9)} [1(^88=80)(^82^8D)(^85^8E)(^81^8F)(^83^90)(^BC^91)(^86^91)(^89=1) (^87^92)(^9A^93)(^8E^94)(^BD=0)(^C3^95)(^9C^86)(^C5^96)(^9D^86) (^8B=3a)(^C0=0)(^C6^99)(^C7=13)(^8A=0)(^C1^9B)]} {FFFFFFFE:^80 {(k^97:c)(s=9)1:m } 1 } {FFFFFFFD:^99 {(k^98:c)(s=9)} [FFFFFFFE(^94^8F)]} <(82=INBOX.test_msf)(83=8082014)(B0=1685531155)(9D=1685531154)(AF=10cc) (87=12)(88=)(89 ={"selectCol":{"visible":false,"ordinal":"1"},"threadCol":{"visible":true,\ "ordinal":"1"},"flaggedCol":{"visible":true,"ordinal":"3"},"attachmentCol":{"v\ isible":true,"ordinal":"5"},"subjectCol":{"visible":true,"ordinal":"7"},"unrea\ dButtonColHeader":{"visible":true,"ordinal":"9"},"senderCol":{"visible":false,\ "ordinal":"11"},"recipientCol":{"visible":false,"ordinal":"13"},"correspondent\ Col":{"visible":true,"ordinal":"15"},"junkStatusCol":{"visible":true,"ordinal"\ :"17"},"receivedCol":{"visible":false,"ordinal":"19"},"dateCol":{"visible":tru\ e,"ordinal":"21"},"statusCol":{"visible":false,"ordinal":"23"},"sizeCol":{"vis\ ible":false,"ordinal":"25"},"tagsCol":{"visible":false,"ordinal":"27"},"accoun\ tCol":{"visible":false,"ordinal":"29"},"priorityCol":{"visible":false,"ordinal\ ":"31"},"unreadCol":{"visible":false,"ordinal":"33"},"totalCol":{"visible":fal\ se,"ordinal":"35"},"locationCol":{"visible":false,"ordinal":"37"},"idCol":{"vi\ sible":false,"ordinal":"39"},"deleteCol":{"visible":false,"ordinal":"13"}}) (8A=2379)(8B=ee00)(8C=5ae7b0cb)> {1:^9E {(k^9F:c)(s=9)} [1(^AB=1)(^AC=0)(^AD=1)(^AE^82)(^88^83)(^A6^82)(^AF^B0)(^B0^9D)(^A0=1) (^A1=1)(^A5=2)(^A8=1)(^A9=1)(^A3^AF)(^B1=12)(^B2=1)(^B3=1)(^B4=0) (^B5=)(^B6^89)(^B7^8A)(^B8^8B)(^A7^8C)(^B9=1)]} <(9F=24abad64-7e29-0766-d7f8-6c2cb444f905@cliss21.org)(9E=test non lu) (A0=64772a0b)(A6=38)(A7=...)(A5=84a)(A9=1104)(AA=4356)> {1:^BA {(k^BB:c)(s=9)} [1(^83^9F)(^82^8D)(^85^8E)(^81^9E)(^BC^A0)(^86^A0)(^C3^95)(^C0=0) (^C6^99)(^C7=38)(^C8^A7)(^9D^A5)(^9C^A9)(^88=80)(^C5^AA)(^89=1)]} @$${B{@ < <(a=c)> // (f=iso-8859-1) (D2=customSortCol)(D3=gloda-id)(D4=gloda-dirty)(D5=notAPhishMessage)> [1:m(^93=0)] [-2:m(^9B=2)(^8F=2)(^91^A0)(^90=0)(^92=1)(^93=1)] <(B3=81)(A1=7f7)> {-1:^80 {(k^96:c)(s=9)} [1(^88=81)] [-2(^88=80)(^82^8D)(^85^8E)(^81^9E)(^83^9F)(^BC^A0)(^86^A0)(^C3^95) (^C0=0)(^C6^99)(^C7=38)(^C8^A7)(^9D^A5)(^9C^A9)(^C5^AA)(^89=1)(^87^A1) (^9A^93)(^8E=2)(^BD=0)]} {-2:^80 {(k^97:c)(s=9)2:m } 2 }[-2:^99(^94^9E)] <(B2=$122)>[-1:^9E(^AB=1)(^AC=0)(^AD=1)(^AE^82)(^88^83)(^A6^82)(^AF^B0) (^B0^9D)(^A0=2)(^A1=1)(^A5=2)(^A8=0)(^A9=0)(^A3^AF)(^B1=12)(^B2=2) (^B3=1)(^B4=0)(^B5^B2)(^B6^89)(^B7=0)(^B8^8B)(^A7^8C)(^B9=2)] {-1:^BA {(k^BB:c)(s=9)} } [-1:^BA] @$$}B}@ @$${C{@ @$$}C}@ @$${D{@ @$$}D}@ @$${E{@ <(B4=2621d)>[1:^80(^D3^B4)] <(B5=26220)>[2:^80(^D3^B5)] <(B6=1685531165)>[1:^9E(^AF^B6)] @$$}E}@ @$${F{@ @$$}F}@
La version décodée:
$VAR1 = [ { 'junkscore' => '0', 'offlineMsgSize' => '84a', 'threadId' => '2', 'dateReceived' => '64772a0b', 'date' => '64772a0b', 'ProtoThreadFlags' => '0', 'priority' => '1', 'recipient_names' => '993|John DOE', 'recipients' => 'John DOE <john.doe@cliss21.org>', 'threadSubject' => 'test non lu', 'threadRoot' => '2', 'sender' => 'John Doe <john.doe@cliss21.org>', 'junkscoreorigin' => 'plugin', 'subject' => 'test non lu', 'msgThreadId' => '2', 'flags' => '80', 'size' => '7f7', 'gloda-id' => '26220', 'msgOffset' => '1104', 'storeToken' => '4356', 'unreadChildren' => '1', 'preview' => '...', 'children' => '1', 'threadParent' => 'ffffffff', 'message-id' => '24abad64-7e29-0766-d7f8-6c2cb444f905@cliss21.org', 'junkpercent' => '38', 'threadFlags' => '0', 'threadNewestMsgDate' => '64772a0b' }, { 'threadSubject' => 'ceci est un test' }, { 'flags' => '8082014', 'numNewMsgs' => '1', 'label' => '0', 'subject' => 'test non lu', 'junkscoreorigin' => 'plugin', 'sortType' => '12', 'numMsgs' => '2', 'gloda-id' => '2621d', 'size' => '82f', 'fixedBadRefThreading' => '1', 'priority' => '1', 'recipient_names' => '993|John DOE', 'expungedBytes' => '10cc', 'ProtoThreadFlags' => '0', 'dateReceived' => '64772a0b', 'junkscore' => '0', 'threadId' => 'fffffffe', 'offlineMsgSize' => '84a', 'forceReparse' => '0', 'threadRoot' => '1', 'sender' => 'John Doe <john.doe@cliss21.org>', 'onlineName' => 'INBOX.test_msf', 'sortOrder' => '2', 'MRUTime' => '1685531165', 'message-id' => '24abad64-7e29-0766-d7f8-6c2cb444f905@cliss21.org', 'columnStates' => '{"selectCol":{"visible":false,"ordinal":"1"},"threadCol":{"visible":true,"ordinal":"1"},"flaggedCol":{"visible":true,"ordinal":"3"},"attachmentCol":{"visible":true,"ordinal":"5"},"subjectCol":{"visible":true,"ordinal":"7"},"unreadButtonColHeader":{"visible":true,"ordinal":"9"},"senderCol":{"visible":false,"ordinal":"11"},"recipientCol":{"visible":false,"ordinal":"13"},"correspondentCol":{"visible":true,"ordinal":"15"},"junkStatusCol":{"visible":true,"ordinal":"17"},"receivedCol":{"visible":false,"ordinal":"19"},"dateCol":{"visible":true,"ordinal":"21"},"statusCol":{"visible":false,"ordinal":"23"},"sizeCol":{"visible":false,"ordinal":"25"},"tagsCol":{"visible":false,"ordinal":"27"},"accountCol":{"visible":false,"ordinal":"29"},"priorityCol":{"visible":false,"ordinal":"31"},"unreadCol":{"visible":false,"ordinal":"33"},"totalCol":{"visible":false,"ordinal":"35"},"locationCol":{"visible":false,"ordinal":"37"},"idCol":{"visible":false,"ordinal":"39"},"deleteCol":{"visible":false,"ordinal":"13"}}', 'keywords' => 'nonjunk', 'threadFlags' => '0', 'version' => '1', 'viewType' => '0', 'highestModSeq' => '0', 'threadParent' => 'ffffffff', 'mailboxName' => 'INBOX.test_msf', 'msgThreadId' => 'fffffffe', 'date' => '64772a0b', 'numLines' => '3a', 'highestRecordedUID' => '2', 'imapFlags' => 'ee00', 'recipients' => 'John DOE <john.doe@cliss21.org>', 'unreadPendingMsgs' => '0', 'totPendingMsgs' => '0', 'UIDValidity' => '5ae7b0cb', 'viewFlags' => '1', 'MRMTime' => '1685531154', 'sortColumns' => '2', 'junkpercent' => '38', 'threadNewestMsgDate' => '647729c3', 'unreadChildren' => '0', 'msgOffset' => '1104', 'storeToken' => '4356', 'highWaterKey' => '2', 'children' => '1', 'preview' => '...' } ];