Email Duplikate in IMAP (Cyrus)

Psimon

Psimon

pSY
Hallo zusammen,

folgendes Szenario: ich habe einen Cyrus IMAP Server auf dem es genau eine Mailbox gibt (nämlich meine). In dieser Mailbox gibt es eine Ordnerstruktur mit eingen tausend Emails, leider auch ettliche Duplikate, die es zu löschen gilt.

Kurzer Hand hab ich gegoogelt und ein nettes Perl Script im tar.gz der IMAP Tools (Quelle: http://www.athensfbc.com/imap_tools/) gefunden, welches diese Aufgabe, das Finden und löschen der Duplikate, meistern soll. Leider findet dieses Script kein einziges meiner Duplikate, obwohl ich doch genau weiß, dass dort duzende vorhanden sind. In anderen Worten, das Script tut nicht wie es soll.

Meine Google Recherge nach etwas anderem, etwas vergleichbaren, führte zu nichts. Wieso sollte man das Rad auch neu erfinden? Also zurück zum Script von IMAP Tools.

Es listet zwar die Ordner auf, überprüft jedoch keine Emails. Es dauert viel zu kurz, dafür das massenhaft Nachrichten da sind und es erscheint letztendlich auch die Meldung "Total messages purged 0", wie ihr wie folgt sehen könnt:

psimongate:/ # perl delIMAPdups.pl -d -S 192.168.0.1/<meinusername>/<meinpassword>

delIMAPdups.pl starting
Connecting to 192.168.0.1
<< * OK PsimonGate Cyrus IMAP4 v2.2.12 server ready
connected to 192.168.0.1
>> 1 LOGIN <meinusername> <meinpassword>
<< 1 OK User logged in
Logged in as <meinusername>
>> 1 LIST "" *
<< * LIST (\HasChildren) "." "INBOX"
<< * LIST (\HasChildren) "." "INBOX.Archiv_Ausgang"
<< * LIST (\HasNoChildren) "." "INBOX.Archiv_Ausgang.2000"
<< * LIST (\HasNoChildren) "." "INBOX.Archiv_Ausgang.2001"
<< * LIST (\HasNoChildren) "." "INBOX.Archiv_Ausgang.2002"
<< * LIST (\HasNoChildren) "." "INBOX.Archiv_Ausgang.2003"
<< * LIST (\HasNoChildren) "." "INBOX.Archiv_Ausgang.2004"
<< * LIST (\HasNoChildren) "." "INBOX.Archiv_Ausgang.2005"
<< * LIST (\HasNoChildren) "." "INBOX.Archiv_Ausgang.2006"
<< * LIST (\HasChildren) "." "INBOX.Archiv_Eingang"
<< * LIST (\HasNoChildren) "." "INBOX.Archiv_Eingang.2000"
<< * LIST (\HasNoChildren) "." "INBOX.Archiv_Eingang.2001"
<< * LIST (\HasNoChildren) "." "INBOX.Archiv_Eingang.2002"
<< * LIST (\HasNoChildren) "." "INBOX.Archiv_Eingang.2003"
<< * LIST (\HasNoChildren) "." "INBOX.Archiv_Eingang.2004"
<< * LIST (\HasNoChildren) "." "INBOX.Archiv_Eingang.2005"
<< * LIST (\HasNoChildren) "." "INBOX.Archiv_Eingang.2006"
<< * LIST (\HasNoChildren) "." "INBOX.Spam"
<< * LIST (\HasChildren) "." "INBOX.wichtiges"
<< * LIST (\HasNoChildren) "." "INBOX.wichtiges.drafts"
<< * LIST (\HasNoChildren) "." "INBOX.wichtiges.ebay"
<< * LIST (\HasNoChildren) "." "INBOX.wichtiges.kskms"
<< * LIST (\HasNoChildren) "." "INBOX.wichtiges.mnet"
<< * LIST (\HasNoChildren) "." "INBOX.wichtiges.mvv"
<< * LIST (\HasNoChildren) "." "INBOX.wichtiges.notizen"
<< * LIST (\HasChildren) "." "INBOX.wichtiges.othas"
<< * LIST (\HasNoChildren) "." "INBOX.wichtiges.othas.foren"
[...]
<< * LIST (\HasNoChildren) "." "INBOX.wichtiges.paypal"
<< * LIST (\HasNoChildren) "." "INBOX.wichtiges.postkarten"
<< * LIST (\HasNoChildren) "." "INBOX.wichtiges.privates"
<< * LIST (\HasNoChildren) "." "INBOX.wichtiges.quittungen"
<< * LIST (\HasNoChildren) "." "INBOX.wichtiges.registrierungen"
<< * LIST (\HasNoChildren) "." "INBOX.wichtiges.vodaphone"
<< * LIST (\HasNoChildren) "." "INBOX.wichtiges.webde"
<< 1 OK Completed (0.000 secs 43 calls)
Looking for duplicate messages
>> 1 LOGOUT
<< * BYE LOGOUT received
<< 1 OK Completed

Total messages purged 0

Nachfolgend die Antwort von 'bytepool', die ich erst gerade im Google Cache gesehen habe (warum dieser Thread gelöscht wurde verstehe ich überhaupt nicht):

hi,

ich habe mir das fragliche Skript mal angeschaut, mir fallen so auf Anhieb 2 Sachen ein:

Erstens, hast du es denn mal mit der Option -p versucht? Bei deinem run oben hast du nur die debug option -d mit angegeben, aber nicht -p, was laut Doku die duplicates loeschen sollte.

Zweitens, bis Zeile 49 scheint ja alles normal durchzulaufen, aber Zeile 55

Code:
print STDOUT "   Checking mailbox $mbx\n";

wird bei deinem Probe run nicht ausgegeben, also wuerde ich die Vermutung aeussern, dass die foreach Schleife nicht durchlaufen wird, weil das Array @mbxs leer ist.
Lass dir doch spasseshalber mal den inhalt von @mbxs ausgeben, also fuege z.B. vor Zeile 49 ein

Code:
print STDOUT "   Inhalt von @mbxs: " . @mbxs . "\n";

@mbxs sollte nicht leer sein, falls doch macht er natuerlich nix.

edit:
Btw., du haettest vielleicht groessere Resonanz gefunden, wenn du das fragliche Skript mal angehangen oder gepostet haettest ;p

mfg,
bytepool

Hierzu ist nun zu sagen, dass die Option -p keinen Unterschied gemacht hat. Die Debugausgabe habe ich in Zeile 49 eingesetzt und bekam folgendes Ergebnis:

Code:
Inhalt von : 0

Heißt also das mbxs tatsächlich leer ist - Schaaaaajseeeee!! Bedeutet wiederrum das die Zeile

Code:
@mbxs = &getMailboxList($sourceUser, 'SRC');

mir kein Array zurückliefert. Was kann ich tun?

Schöne Grüße,
Simon
 
Zuletzt bearbeitet:
Aha

Hallo zusammen,

ich konnte den Fehler mit Logging-Ausgaben eingrenzen. Der Fehler liegt in der folgenden Zeile:

Code:
($dmy,$mbx) = split(/"\/"/,$response[$i]);

Hier wird nichts gesplittet und $dmy beinhaltet den kompletten $response[$i] String, wie ihr wie folgt sehen könnt:

Code:
* LIST (\HasChildren) "." "INBOX" is splitted into mbx:  and dmy: * LIST (\HasChildren) "." "INBOX"
* LIST (\HasChildren) "." "INBOX.Archiv_Ausgang" is splitted into mbx:  and dmy: * LIST (\HasChildren) "." "INBOX.Archiv_Ausgang"
* LIST (\HasNoChildren) "." "INBOX.Archiv_Ausgang.2000" is splitted into mbx:  and dmy: * LIST (\HasNoChildren) "." "INBOX.Archiv_Ausgang.2000"
* LIST (\HasNoChildren) "." "INBOX.Archiv_Ausgang.2001" is splitted into mbx:  and dmy: * LIST (\HasNoChildren) "." "INBOX.Archiv_Ausgang.2001"
* LIST (\HasNoChildren) "." "INBOX.Archiv_Ausgang.2002" is splitted into mbx:  and dmy: * LIST (\HasNoChildren) "." "INBOX.Archiv_Ausgang.2002"
* LIST (\HasNoChildren) "." "INBOX.Archiv_Ausgang.2003" is splitted into mbx:  and dmy: * LIST (\HasNoChildren) "." "INBOX.Archiv_Ausgang.2003"
* LIST (\HasNoChildren) "." "INBOX.Archiv_Ausgang.2004" is splitted into mbx:  and dmy: * LIST (\HasNoChildren) "." "INBOX.Archiv_Ausgang.2004"
* LIST (\HasNoChildren) "." "INBOX.Archiv_Ausgang.2005" is splitted into mbx:  and dmy: * LIST (\HasNoChildren) "." "INBOX.Archiv_Ausgang.2005"
* LIST (\HasNoChildren) "." "INBOX.Archiv_Ausgang.2006" is splitted into mbx:  and dmy: * LIST (\HasNoChildren) "." "INBOX.Archiv_Ausgang.2006"
[...]

Kann mir jemand bitte diese Zeile korrigieren?

Liebe Grüße,
Simon
 
hi,

waere das nicht die perfekte Gelegenheit ein wenig perl zu lernen? ;)
Fuer so Skripting Sachen finde ich Perl toll, solange ich damit kein OO Projekt machen muss... ;)

Also, wenn man sich das so anguckt, ist das ja auch logisch dass er da nichts splittet.
Code:
split(/"\/"/,$response[$i])
sollte eigentlich bewirken, dass "/" als Delimiter genutzt wird, aber das kommt in dem String ja gar nicht vor. Versuch dochmal den / durch einen Punkt (.) zu ersetzen. Also so:
Code:
($dmy,$mbx) = split(/"\."/,$response[$i]);

Wenn ich den Sinn dahinter richtig verstehe, sollte das schon dein Problem loesen. Im uebrigen bin ich mir nicht sicher ob der Punkt (.) escaped werden muss, aber es kann eigentlich auch nicht schaden ;)

mfg,
bytepool
 
Zuletzt bearbeitet:
hallo bytepool,

schon bevor du geschrieben hast hab ich mir perl zu gemüte gezogen und ein wenig hausaufgaben in regex gemacht. da ich java programmierer bin ist mir das alles ja glücklicherweise nicht so fremd. ;)

der author der delIMAPdups.pl hat jedenfalls schon sehr gute vorarbeit geleistet und ich bin sicher, dass das script bei ihm auf dem rechner tüchtig funktioniert hat. jedoch sind auf meinem imap (Cyrus IMAP4 v2.2.12) zwei bugs aufgetaucht, wenn man es aktuell von der homepage (siehe erstes posting) bezieht.

#1: das script kann nicht mit leeren ordern umgehen und bleibt im scanning stehen. wenn man einen ordner mit emails mit dem argument -m mit gibt, funktioniert es tadellos.

#2: die uid, die eine jede email eindeutig identifiziert, wurde nicht richtig aus dem header ausgelesen und somit wurden auch keine duplikate erkannt. die regexpression hat an dieser stelle überhaupt nicht gestimmt. ich gehe davon aus das der author einen anderen imap server besitzt und die rc konventionen schlicht und ergreifend nicht identisch sind.

jedenfalls tut es jetzt:)

...und selbstverständlich möchte ich das dir und den anderen nicht vorenthalten! eine weitere nachricht folgt daher in kürze.

besten dank an deinen support bytepool!

grüße,
simon
 
...und selbstverständlich möchte ich das dir und den anderen nicht vorenthalten! eine weitere nachricht folgt daher in kürze.

Es gibt leider doch noch ein Problem bei meinen letzten Tests. Und zwar wird an dieser Stelle ein IMAP Command geschickt, dass eigentlich bewirken müßte das die 13 Messages, mit Komma aneinander gereihten UID's als gelöscht markiert werden.

>> 1 STORE 61,67,58,62,64,55,63,59,35,65,60 +FLAGS (\Deleted)
<< * 35 FETCH (FLAGS (\Deleted \Seen))
<< 1 OK Completed

Leider wird lediglich eine (die UID 35) zum Löschen markiert. Was geht da vor sich? Das IMAP Command ist definitiv in Ordnung!

Grüße,
Simon
 
Der Fehler ist gefunden! Bei dem IMAP Kommando
Code:
1 STORE 515, 518, 520 +FLAGS (\Deleted)
muss beachtet werden, dass IMAP die Nummer der Email möchte, jedoch nicht die UID, wie anfangs gedacht. Sehr seltsam, aber wahr!

Nachfolgend ein Snippchen aus meiner Telnet Session mit dem Cyrus IMAP:

Code:
[...]
* 555 FETCH (UID 745)
* 556 FETCH (UID 980)
* 557 FETCH (UID 981)
* 558 FETCH (UID 982)
* 559 FETCH (UID 983)
* 560 FETCH (UID 984)
* 561 FETCH (UID 987)
1 OK Completed (0.000 sec)
1 STORE 561 +FLAGS (\Deleted)
* 561 FETCH (FLAGS (\Deleted \Seen))
1 OK Completed
1 EXPUNGE
* 561 EXPUNGE
* 560 EXISTS
* 0 RECENT
1 OK Completed
1 FETCH 1:1000 (uid)
[...]
* 555 FETCH (UID 745)
* 556 FETCH (UID 980)
* 557 FETCH (UID 981)
* 558 FETCH (UID 982)
* 559 FETCH (UID 983)
* 560 FETCH (UID 984)
1 OK Completed (0.010 sec)
 
Das wars! => Total messages purged 4031 :)

Das Perl Script muss wie folgt aufgerufen werden:
perl delIMAPdups2.pl -S meinhostname/meinusername/meinpasswort

-m INBOX.Archiv_Eingang.2001 (Optional ein bestimmtes Verzeichnis angeben)
-p (Optional löscht dieser Parameter die Emails endgültig, falls -p nicht angegeben wird, werden die Emails mit dem \Deleted Flag versehen)
-d (Ebenfalls Optional, Debug Ausgaben fürs Matching und IMAP Server kommunikation)

Und hier das überarbeitete Perl Script:
 

Anhänge

  • delIMAPdups2.zip
    5,4 KB · Aufrufe: 2
Hallo zusammen,

ich hab noch einen Bug gefixt, sowie die Logging-Ausgaben optimiert. Werde das aktuelle Script nachher nochmal hinterlegen.

Liebe Grüße,
Simon
 

Ähnliche Themen

dovecot und postfix Konfiguration Problem

NagiosGrapher 1.7.1 funktioniert nicht

Exim + Cyrus-IMAP Fehler bei der Einlieferung

squid transparent proxy will nicht transparent werden !! :-(

Apache zu langsam ?

Zurück
Oben