MailImporter

filteropera.cpp
1/*
2 filteropera.cpp - Opera mail import
3
4 SPDX-FileCopyrightText: 2005 Danny Kukawka <danny.kukawka@web.de>
5
6 SPDX-License-Identifier: GPL-2.0-or-later
7*/
8
9#include "filteropera.h"
10
11#include <KLocalizedString>
12
13#include <QFileDialog>
14#include <QTemporaryFile>
15
16using namespace MailImporter;
17
18FilterOpera::FilterOpera()
19 : Filter(i18n("Import Opera Emails"),
20 QStringLiteral("Danny Kukawka"),
21 i18n("<p><b>Opera email import filter</b></p>"
22 "<p>This filter will import mails from Opera mail folder. Use this filter "
23 "if you want to import all mails within a account in the Opera maildir.</p>"
24 "<p>Select the directory of the account (usually ~/.opera/mail/store/account*).</p>"
25 "<p><b>Note:</b> Emails will be imported into a folder named after the account "
26 "they came from, prefixed with OPERA-</p>"))
27{
28}
29
30FilterOpera::~FilterOpera()
31{
32}
33
34QString FilterOpera::isMailerFound()
35{
36 QDir directory(FilterOpera::defaultSettingsPath());
37 if (directory.exists()) {
38 return i18nc("name of opera application", "Opera");
39 }
40 return {};
41}
42
43QString FilterOpera::defaultSettingsPath()
44{
45 return QDir::homePath() + QLatin1StringView("/.opera/");
46}
47
48void FilterOpera::importRecursive(const QDir &mailDir, const QString &accountName)
49{
50 // Recursive import of the MBoxes.
51 const QStringList rootSubDirs = mailDir.entryList(QStringList(QStringLiteral("[^\\.]*")), QDir::Dirs, QDir::Name); // Removal of . and ..
52 int numSubDirs = rootSubDirs.size();
53 if (numSubDirs > 0) {
55 for (QStringList::ConstIterator filename = rootSubDirs.constBegin(); filename != end; ++filename) {
56 QDir importDir(mailDir.path() + QLatin1Char('/') + *filename);
57 const QStringList files = importDir.entryList(QStringList(QStringLiteral("*.[mM][bB][sS]")), QDir::Files, QDir::Name);
58 if (files.isEmpty()) {
59 importRecursive(importDir, accountName.isEmpty() ? *filename : accountName);
60 } else {
61 importBox(importDir, files, accountName);
62 }
63 }
64 }
65}
66
67void FilterOpera::importBox(const QDir &importDir, const QStringList &files, const QString &accountName)
68{
69 int overall_status = 0;
70 int totalFiles = files.count();
71 int currentFile = 1;
72 filterInfo()->addInfoLogEntry(i18n("Importing new mail files..."));
74 for (QStringList::ConstIterator mailFile = files.constBegin(); mailFile != end; ++mailFile) {
75 filterInfo()->setCurrent(0);
76 QFile operaArchiv(importDir.filePath(*mailFile));
77 if (!operaArchiv.open(QIODevice::ReadOnly)) {
78 filterInfo()->alert(i18n("Unable to open %1, skipping", *mailFile));
79 } else {
80 filterInfo()->addInfoLogEntry(i18n("Importing emails from %1...", *mailFile));
81 QFileInfo filenameInfo(importDir.filePath(*mailFile));
82 QString folderName;
83 if (accountName.isEmpty()) {
84 folderName = QString(QLatin1StringView("OPERA-") + importDir.dirName());
85 } else {
86 folderName = QString(QLatin1StringView("OPERA-") + accountName);
87 }
88
89 filterInfo()->setFrom(*mailFile);
90 filterInfo()->setTo(folderName);
91
92 QByteArray input(MAX_LINE, '\0');
93 long l = 0;
94 bool first_msg = true;
95
96 while (!operaArchiv.atEnd()) {
98 tmp.open();
99 /* comment by Danny:
100 * Don't use QTextStream to read from mbox, better use QDataStream. QTextStream only
101 * support Unicode/Latin1/Locale. So you lost information from emails with
102 * charset!=Unicode/Latin1/Locale (e.g. KOI8-R) and Content-Transfer-Encoding != base64
103 * (e.g. 8Bit). It also not help to convert the QTextStream to Unicode. By this you
104 * get Unicode/UTF-email but KMail can't detect the correct charset.
105 */
106 QByteArray separate;
107
108 if (!first_msg) {
109 tmp.write(input.constData(), l);
110 }
111 l = operaArchiv.readLine(input.data(), MAX_LINE); // read the first line, prevent "From "
112 tmp.write(input.constData(), l);
113
114 while (!operaArchiv.atEnd() && (l = operaArchiv.readLine(input.data(), MAX_LINE)) && ((separate = input.data()).left(5) != "From ")) {
115 /** remove in KMail unneeded Flags from Opera (for example: X-Opera-Status)*/
116 if (separate.left(8) != "X-Opera-") {
117 tmp.write(input.constData(), l);
118 }
119 }
120 tmp.flush();
121 first_msg = false;
122
123 if (!importMessage(folderName, tmp.fileName(), filterInfo()->removeDupMessage())) {
124 filterInfo()->addErrorLogEntry(i18n("Could not import %1", tmp.fileName()));
125 }
126 int currentPercentage = (int)(((float)operaArchiv.pos() / filenameInfo.size()) * 100);
127 filterInfo()->setCurrent(currentPercentage);
128
129 if (currentFile == 1) {
130 overall_status = (int)(currentPercentage * ((float)currentFile / totalFiles));
131 } else {
132 overall_status = (int)(((currentFile - 1) * (100.0 / (float)totalFiles)) + (currentPercentage * (1.0 / (float)totalFiles)));
133 }
134
135 filterInfo()->setOverall(overall_status);
136 if (filterInfo()->shouldTerminate()) {
137 break;
138 }
139 }
140
141 filterInfo()->addInfoLogEntry(i18n("Finished importing emails from %1", *mailFile));
142 if (countDuplicates() > 0) {
143 filterInfo()->addInfoLogEntry(i18np("1 duplicate message not imported", "%1 duplicate messages not imported", countDuplicates()));
144 }
145 currentFile++;
146 clearCountDuplicate();
147 operaArchiv.close();
148 }
149 if (filterInfo()->shouldTerminate()) {
150 break;
151 }
152 }
153}
154
156{
157 /** try to go to opera mailfolder in the home of the user */
158 QString startdir = defaultSettingsPath() + QLatin1StringView("mail/store/");
159 QDir d(startdir);
160 if (!d.exists()) {
161 startdir = QDir::homePath();
162 }
163
164 const QString maildir = QFileDialog::getExistingDirectory(nullptr, QString(), startdir);
165 if (!maildir.isEmpty()) {
166 importMails(maildir);
167 }
168}
169
171{
172 setMailDir(maildir);
173 if (mailDir().isEmpty()) {
174 filterInfo()->alert(i18n("No directory selected."));
175 return;
176 }
177 /**
178 * If the user only select homedir no import needed because
179 * there should be no files and we surely import wrong files.
180 */
181 else if (mailDir() == QDir::homePath() || mailDir() == (QDir::homePath() + QLatin1Char('/'))) {
182 filterInfo()->addErrorLogEntry(i18n("No files found for import."));
183 } else {
184 filterInfo()->setOverall(0);
185
186 QDir importDir(mailDir());
187 const QStringList files = importDir.entryList(QStringList(QStringLiteral("*.[mM][bB][sS]")), QDir::Files, QDir::Name);
188
189 // Count total number of files to be processed
190 filterInfo()->addInfoLogEntry(i18n("Counting files..."));
191
192 if (!files.isEmpty()) {
193 importBox(importDir, files);
194 } else {
195 // opera > 9.10 stores mail in subfolder.
196 importRecursive(importDir);
197 }
198 }
199 if (filterInfo()->shouldTerminate()) {
200 filterInfo()->addInfoLogEntry(i18n("Finished import, canceled by user."));
201 }
202 filterInfo()->setCurrent(100);
203 filterInfo()->setOverall(100);
204}
void importMails(const QString &maildir)
QString i18np(const char *singular, const char *plural, const TYPE &arg...)
QString i18nc(const char *context, const char *text, const TYPE &arg...)
QString i18n(const char *text, const TYPE &arg...)
const QList< QKeySequence > & end()
QByteArray left(qsizetype len) const const
QString dirName() const const
QStringList entryList(Filters filters, SortFlags sort) const const
bool exists() const const
QString filePath(const QString &fileName) const const
QString homePath()
QString path() const const
bool flush()
QString getExistingDirectory(QWidget *parent, const QString &caption, const QString &dir, Options options)
qint64 write(const QByteArray &data)
typedef ConstIterator
const_iterator constBegin() const const
const_iterator constEnd() const const
qsizetype count() const const
bool isEmpty() const const
qsizetype size() 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 Tue Mar 26 2024 11:17:39 by doxygen 1.10.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.