diff options
author | Christian Mollekopf <chrigi_1@fastmail.fm> | 2016-10-20 13:34:38 +0200 |
---|---|---|
committer | Christian Mollekopf <chrigi_1@fastmail.fm> | 2016-10-21 09:18:50 +0200 |
commit | da0c37dbad121252effa85941de4d49222176179 (patch) | |
tree | 6ea9831e80fc18dcae00cdf2788680bb8f4d1935 /common/mail/threadindexer.cpp | |
parent | 0dcc8e2985acbff52c497648e4fbb54e47bf3b51 (diff) | |
download | sink-da0c37dbad121252effa85941de4d49222176179.tar.gz sink-da0c37dbad121252effa85941de4d49222176179.zip |
A new indexer subsystem that can be used for indexes that are more
complex than a simple key-value pair.
Diffstat (limited to 'common/mail/threadindexer.cpp')
-rw-r--r-- | common/mail/threadindexer.cpp | 140 |
1 files changed, 140 insertions, 0 deletions
diff --git a/common/mail/threadindexer.cpp b/common/mail/threadindexer.cpp new file mode 100644 index 0000000..4a18625 --- /dev/null +++ b/common/mail/threadindexer.cpp | |||
@@ -0,0 +1,140 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2015 Christian Mollekopf <chrigi_1@fastmail.fm> | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License as published by | ||
6 | * the Free Software Foundation; either version 2 of the License, or | ||
7 | * (at your option) any later version. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, | ||
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | * GNU General Public License for more details. | ||
13 | * | ||
14 | * You should have received a copy of the GNU General Public License | ||
15 | * along with this program; if not, write to the | ||
16 | * Free Software Foundation, Inc., | ||
17 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | ||
18 | */ | ||
19 | #include "threadindexer.h" | ||
20 | |||
21 | #include "typeindex.h" | ||
22 | #include "log.h" | ||
23 | |||
24 | SINK_DEBUG_AREA("threadindex") | ||
25 | |||
26 | using namespace Sink; | ||
27 | using namespace Sink::ApplicationDomain; | ||
28 | |||
29 | static QString stripOffPrefixes(const QString &subject) | ||
30 | { | ||
31 | //TODO this hardcoded list is probably not good enough (especially regarding internationalization) | ||
32 | //TODO this whole routine, including internationalized re/fwd ... should go into some library. | ||
33 | //We'll require the same for generating reply/forward subjects in kube | ||
34 | static QStringList defaultReplyPrefixes = QStringList() << QLatin1String("Re\\s*:") | ||
35 | << QLatin1String("Re\\[\\d+\\]:") | ||
36 | << QLatin1String("Re\\d+:"); | ||
37 | |||
38 | static QStringList defaultForwardPrefixes = QStringList() << QLatin1String("Fwd:") | ||
39 | << QLatin1String("FW:"); | ||
40 | |||
41 | QStringList replyPrefixes; // = GlobalSettings::self()->replyPrefixes(); | ||
42 | if (replyPrefixes.isEmpty()) { | ||
43 | replyPrefixes = defaultReplyPrefixes; | ||
44 | } | ||
45 | |||
46 | QStringList forwardPrefixes; // = GlobalSettings::self()->forwardPrefixes(); | ||
47 | if (forwardPrefixes.isEmpty()) { | ||
48 | forwardPrefixes = defaultReplyPrefixes; | ||
49 | } | ||
50 | |||
51 | const QStringList prefixRegExps = replyPrefixes + forwardPrefixes; | ||
52 | |||
53 | // construct a big regexp that | ||
54 | // 1. is anchored to the beginning of str (sans whitespace) | ||
55 | // 2. matches at least one of the part regexps in prefixRegExps | ||
56 | const QString bigRegExp = QString::fromLatin1("^(?:\\s+|(?:%1))+\\s*").arg(prefixRegExps.join(QLatin1String(")|(?:"))); | ||
57 | |||
58 | static QString regExpPattern; | ||
59 | static QRegExp regExp; | ||
60 | |||
61 | regExp.setCaseSensitivity(Qt::CaseInsensitive); | ||
62 | if (regExpPattern != bigRegExp) { | ||
63 | // the prefixes have changed, so update the regexp | ||
64 | regExpPattern = bigRegExp; | ||
65 | regExp.setPattern(regExpPattern); | ||
66 | } | ||
67 | |||
68 | if(regExp.isValid()) { | ||
69 | QString tmp = subject; | ||
70 | if (regExp.indexIn( tmp ) == 0) { | ||
71 | return tmp.remove(0, regExp.matchedLength()); | ||
72 | } | ||
73 | } else { | ||
74 | SinkWarning() << "bigRegExp = \"" | ||
75 | << bigRegExp << "\"\n" | ||
76 | << "prefix regexp is invalid!"; | ||
77 | } | ||
78 | |||
79 | return subject; | ||
80 | } | ||
81 | |||
82 | |||
83 | void ThreadIndexer::updateThreadingIndex(const QByteArray &identifier, const ApplicationDomain::ApplicationDomainType &entity, Sink::Storage::DataStore::Transaction &transaction) | ||
84 | { | ||
85 | auto messageId = entity.getProperty(Mail::MessageId::name); | ||
86 | auto parentMessageId = entity.getProperty(Mail::ParentMessageId::name); | ||
87 | auto subject = entity.getProperty(Mail::Subject::name); | ||
88 | |||
89 | auto normalizedSubject = stripOffPrefixes(subject.toString()).toUtf8(); | ||
90 | |||
91 | QVector<QByteArray> thread; | ||
92 | |||
93 | //a child already registered our thread. | ||
94 | thread = index().secondaryLookup<Mail::MessageId, Mail::ThreadId>(messageId, transaction); | ||
95 | |||
96 | //If parent is already available, add to thread of parent | ||
97 | if (thread.isEmpty() && parentMessageId.isValid()) { | ||
98 | thread = index().secondaryLookup<Mail::MessageId, Mail::ThreadId>(parentMessageId, transaction); | ||
99 | SinkTrace() << "Found parent"; | ||
100 | } | ||
101 | if (thread.isEmpty()) { | ||
102 | //Try to lookup the thread by subject: | ||
103 | thread = index().secondaryLookup<Mail::Subject, Mail::ThreadId>(normalizedSubject, transaction); | ||
104 | if (thread.isEmpty()) { | ||
105 | SinkTrace() << "Created a new thread "; | ||
106 | thread << QUuid::createUuid().toByteArray(); | ||
107 | } else { | ||
108 | } | ||
109 | } | ||
110 | |||
111 | //We should have found the thread by now | ||
112 | if (!thread.isEmpty()) { | ||
113 | if (parentMessageId.isValid()) { | ||
114 | //Register parent with thread for when it becomes available | ||
115 | index().index<Mail::MessageId, Mail::ThreadId>(parentMessageId, thread.first(), transaction); | ||
116 | } | ||
117 | index().index<Mail::MessageId, Mail::ThreadId>(messageId, thread.first(), transaction); | ||
118 | index().index<Mail::ThreadId, Mail::MessageId>(thread.first(), messageId, transaction); | ||
119 | index().index<Mail::Subject, Mail::ThreadId>(normalizedSubject, thread.first(), transaction); | ||
120 | } else { | ||
121 | SinkWarning() << "Couldn't find a thread for: " << messageId; | ||
122 | } | ||
123 | } | ||
124 | |||
125 | |||
126 | void ThreadIndexer::add(const ApplicationDomain::ApplicationDomainType &entity) | ||
127 | { | ||
128 | updateThreadingIndex(entity.identifier(), entity, transaction()); | ||
129 | } | ||
130 | |||
131 | void ThreadIndexer::modify(const ApplicationDomain::ApplicationDomainType &old, const ApplicationDomain::ApplicationDomainType &entity) | ||
132 | { | ||
133 | |||
134 | } | ||
135 | |||
136 | void ThreadIndexer::remove(const ApplicationDomain::ApplicationDomainType &entity) | ||
137 | { | ||
138 | |||
139 | } | ||
140 | |||