MailImporter

filtermailmangzip.cpp
1/*
2 SPDX-FileCopyrightText: 2013-2024 Laurent Montel <montel@kde.org>
3
4 SPDX-License-Identifier: GPL-2.0-or-later
5*/
6
7#include "filtermailmangzip.h"
8#include "mailimporter_debug.h"
9
10#include <KCompressionDevice>
11#include <KLocalizedString>
12
13#include <QFileDialog>
14#include <QTemporaryFile>
15
16using namespace MailImporter;
17
18FilterMailmanGzip::FilterMailmanGzip()
19 : Filter(i18n("Import mailman gzip Files"),
20 QStringLiteral("Laurent Montel"),
21 i18n("<p><b>mailman gzip import filter</b></p>"
22 "<p>This filter will import mailman gzipped files into KMail.</p>"
23 "<p><b>Note:</b> Emails will be imported into folders named after the "
24 "file they came from, prefixed with MAILMAN-</p>"))
25{
26}
27
28FilterMailmanGzip::~FilterMailmanGzip()
29{
30}
31
32void FilterMailmanGzip::import()
33{
34 const QStringList filenames =
35 QFileDialog::getOpenFileNames(filterInfo()->parentWidget(), QString(), QDir::homePath(), QStringLiteral("%1 (*.txt.gz)").arg(i18n("gzip Files")));
36 importMails(filenames);
37}
38
39void FilterMailmanGzip::importMails(const QStringList &filenames)
40{
41 if (filenames.isEmpty()) {
42 filterInfo()->alert(i18n("No files selected."));
43 return;
44 }
45 int currentFile = 1;
46 int overall_status = 0;
47 bool first_msg = true;
48
49 filterInfo()->setOverall(0);
51 for (QStringList::ConstIterator filename = filenames.constBegin(); filename != end; ++filename, ++currentFile) {
52 QIODevice *device = new KCompressionDevice(*filename, KCompressionDevice::GZip);
53 if (!device) {
54 qCDebug(MAILIMPORTER_LOG) << "Could not create KFilterDev";
55 filterInfo()->alert(i18n("Unable to open archive file '%1', skipping", *filename));
56 continue;
57 }
58
60 QFileInfo filenameInfo(*filename);
61 QString folderName(QLatin1StringView("MAILMAN-") + filenameInfo.completeBaseName());
62
63 filterInfo()->setCurrent(0);
64 filterInfo()->addInfoLogEntry(i18n("Importing emails from %1...", *filename));
65
66 filterInfo()->setFrom(*filename);
67 filterInfo()->setTo(folderName);
68
69 QByteArray input(MAX_LINE, '\0');
70 long l = 0;
71
72 while (!device->atEnd()) {
74 tmp.open();
75 qint64 filepos = 0;
76 /* comment by Danny:
77 * Don't use QTextStream to read from mbox, better use QDataStream. QTextStream only
78 * support Unicode/Latin1/Locale. So you lost information from emails with
79 * charset!=Unicode/Latin1/Locale (e.g. KOI8-R) and Content-Transfer-Encoding != base64
80 * (e.g. 8Bit). It also not help to convert the QTextStream to Unicode. By this you
81 * get Unicode/UTF-email but KMail can't detect the correct charset.
82 */
83 QByteArray separate;
84
85 /* check if the first line start with "From " (and not "From: ") and discard the line
86 * in this case because some IMAP servers (e.g. Cyrus) don't accept this header line */
87 if (!first_msg && ((separate = input.data()).left(5) != "From ")) {
88 tmp.write(input.constData(), l);
89 }
90
91 l = device->readLine(input.data(), MAX_LINE); // read the first line, prevent "From "
92
93 if ((separate = input.data()).left(5) != "From ") {
94 separate.replace(" at ", "@");
95 tmp.write(separate.constData(), separate.length());
96 }
97
98 while (!device->atEnd() && (l = device->readLine(input.data(), MAX_LINE)) && ((separate = input.data()).left(5) != "From ")) {
99 tmp.write(input.constData(), l);
100
101 // workaround to fix hang if a corrupted mbox contains some
102 // binary data, for more see bug #106796
103 if (device->pos() == filepos) {
104 device->seek(device->size());
105 } else {
106 filepos = device->pos();
107 }
108 }
109 tmp.flush();
110 first_msg = false;
111
112 if (tmp.size() > 0) {
113 if (!importMessage(folderName, tmp.fileName(), filterInfo()->removeDupMessage())) {
114 filterInfo()->addErrorLogEntry(i18n("Could not import %1", tmp.fileName()));
115 }
116 } else {
117 qCWarning(MAILIMPORTER_LOG) << "Message size is 0 bytes, not importing it.";
118 }
119
120 int currentPercentage = (int)(((float)device->pos() / filenameInfo.size()) * 100);
121 filterInfo()->setCurrent(currentPercentage);
122 if (currentFile == 1) {
123 overall_status = (int)(currentPercentage * ((float)currentFile / filenames.count()));
124 } else {
125 overall_status = (int)(((currentFile - 1) * (100.0 / (float)filenames.count())) + (currentPercentage * (1.0 / (float)filenames.count())));
126 }
127 filterInfo()->setOverall(overall_status);
128
129 if (filterInfo()->shouldTerminate()) {
130 break;
131 }
132 }
133
134 filterInfo()->addInfoLogEntry(i18n("Finished importing emails from %1", *filename));
135 if (countDuplicates() > 0) {
136 filterInfo()->addInfoLogEntry(i18np("1 duplicate message not imported to folder %2 in KMail",
137 "%1 duplicate messages not imported to folder %2 in KMail",
138 countDuplicates(),
139 folderName));
140 }
141 if (filterInfo()->shouldTerminate()) {
142 filterInfo()->addInfoLogEntry(i18n("Finished import, canceled by user."));
143 }
144
145 clearCountDuplicate();
146 // don't forget to close the file !!!
147 device->close();
148 delete device;
149 }
150}
QString i18np(const char *singular, const char *plural, const TYPE &arg...)
QString i18n(const char *text, const TYPE &arg...)
const QList< QKeySequence > & end()
const char * constData() const const
qsizetype length() const const
QByteArray & replace(QByteArrayView before, QByteArrayView after)
QString homePath()
virtual qint64 size() const const override
bool flush()
QStringList getOpenFileNames(QWidget *parent, const QString &caption, const QString &dir, const QString &filter, QString *selectedFilter, Options options)
virtual bool atEnd() const const
virtual void close()
virtual bool open(QIODeviceBase::OpenMode mode)
virtual qint64 pos() const const
QByteArray readLine(qint64 maxSize)
virtual bool seek(qint64 pos)
virtual qint64 size() const const
qint64 write(const QByteArray &data)
const_iterator constBegin() const const
const_iterator constEnd() const const
qsizetype count() const const
bool isEmpty() const const
virtual QString fileName() const const override
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Fri Dec 6 2024 12:08:02 by doxygen 1.12.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.