1/*
2 Copyright (c) 2007 Volker Krause <vkrause@kde.org>
3
4 This library is free software; you can redistribute it and/or modify it
5 under the terms of the GNU Library General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or (at your
7 option) any later version.
8
9 This library is distributed in the hope that it will be useful, but WITHOUT
10 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public
12 License for more details.
13
14 You should have received a copy of the GNU Library General Public License
15 along with this library; see the file COPYING.LIB. If not, write to the
16 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17 02110-1301, USA.
18*/
19
20#include "imapset.h"
21
22#include <QtCore/QSharedData>
23
24using namespace KIMAP;
25
26class ImapInterval::Private : public QSharedData
27{
28 public:
29 Private() :
30 QSharedData(),
31 begin( 0 ),
32 end( 0 )
33 {}
34
35 Private( const Private &other ) :
36 QSharedData( other )
37 {
38 begin = other.begin;
39 end = other.end;
40 }
41
42 Id begin;
43 Id end;
44};
45
46class ImapSet::Private : public QSharedData
47{
48 public:
49 Private() : QSharedData() {}
50 Private( const Private &other ) :
51 QSharedData( other )
52 {
53 intervals = other.intervals;
54 }
55
56 ImapInterval::List intervals;
57};
58
59ImapInterval::ImapInterval() :
60 d( new Private )
61{
62}
63
64ImapInterval::ImapInterval(const ImapInterval & other) :
65 d( other.d )
66{
67}
68
69ImapInterval::ImapInterval(Id begin, Id end) :
70 d( new Private )
71{
72 d->begin = begin;
73 d->end = end;
74}
75
76ImapInterval::~ ImapInterval()
77{
78}
79
80ImapInterval& ImapInterval::operator =(const ImapInterval & other)
81{
82 if ( this != &other ) {
83 d = other.d;
84 }
85 return *this;
86}
87
88bool ImapInterval::operator ==(const ImapInterval & other) const
89{
90 return ( d->begin == other.d->begin && d->end == other.d->end );
91}
92
93ImapInterval::Id ImapInterval::size() const
94{
95 if ( !d->begin && !d->end ) {
96 return 0;
97 }
98 if ( d->begin && !d->end ) {
99 return Q_INT64_C( 0x7FFFFFFFFFFFFFFF ) - d->begin + 1;
100 }
101 return d->end - d->begin + 1;
102}
103
104bool ImapInterval::hasDefinedBegin() const
105{
106 return d->begin != 0;
107}
108
109ImapInterval::Id ImapInterval::begin() const
110{
111 return d->begin;
112}
113
114bool ImapInterval::hasDefinedEnd() const
115{
116 return d->end != 0;
117}
118
119ImapInterval::Id ImapInterval::end() const
120{
121 if ( hasDefinedEnd() ) {
122 return d->end;
123 }
124 return 0xFFFFFFFF; // should be INT_MAX, but where is that defined again?
125}
126
127void ImapInterval::setBegin(Id value)
128{
129 Q_ASSERT( value >= 0 );
130 Q_ASSERT( value <= d->end || !hasDefinedEnd() );
131 d->begin = value;
132}
133
134void ImapInterval::setEnd(Id value)
135{
136 Q_ASSERT( value >= 0 );
137 Q_ASSERT( value >= d->begin || !hasDefinedBegin() );
138 d->end = value;
139}
140
141QByteArray ImapInterval::toImapSequence() const
142{
143 if ( size() == 0 ) {
144 return QByteArray();
145 }
146 if ( size() == 1 ) {
147 return QByteArray::number( d->begin );
148 }
149 QByteArray rv;
150 rv += QByteArray::number( d->begin ) + ':';
151 if ( hasDefinedEnd() ) {
152 rv += QByteArray::number( d->end );
153 } else {
154 rv += '*';
155 }
156 return rv;
157}
158
159ImapInterval ImapInterval::fromImapSequence( const QByteArray &sequence )
160{
161 QList<QByteArray> values = sequence.split( ':' );
162 if ( values.isEmpty() || values.size() > 2 ) {
163 return ImapInterval();
164 }
165
166 bool ok = false;
167 Id begin = values[0].toLongLong( &ok );
168
169 if ( !ok ) {
170 return ImapInterval();
171 }
172
173 Id end;
174
175 if ( values.size() == 1 ) {
176 end = begin;
177 } else if ( values[1] == QByteArray( "*" ) ) {
178 end = 0;
179 } else {
180 ok = false;
181 end = values[1].toLongLong( &ok );
182 if ( !ok ) {
183 return ImapInterval();
184 }
185 }
186
187 return ImapInterval( begin, end );
188}
189
190ImapSet::ImapSet() :
191 d( new Private )
192{
193}
194
195ImapSet::ImapSet( Id begin, Id end ) :
196 d( new Private )
197{
198 add( ImapInterval( begin, end ) );
199}
200
201ImapSet::ImapSet( Id value ) :
202 d( new Private )
203{
204 add( QList<Id>() << value );
205}
206
207ImapSet::ImapSet(const ImapSet & other) :
208 d( other.d )
209{
210}
211
212ImapSet::~ImapSet()
213{
214}
215
216ImapSet & ImapSet::operator =(const ImapSet & other)
217{
218 if ( this != &other ) {
219 d = other.d;
220 }
221 return *this;
222}
223
224bool ImapSet::operator ==(const ImapSet &other) const
225{
226 if ( d->intervals.size()!=other.d->intervals.size() ) {
227 return false;
228 }
229
230 foreach ( const ImapInterval &interval, d->intervals ) {
231 if ( !other.d->intervals.contains( interval ) ) {
232 return false;
233 }
234 }
235
236 return true;
237}
238
239void ImapSet::add( Id value )
240{
241 add( QList<Id>() << value );
242}
243
244void ImapSet::add(const QList<Id> & values)
245{
246 QList<Id> vals = values;
247 qSort( vals );
248 for ( int i = 0; i < vals.count(); ++i ) {
249 const int begin = vals[i];
250 Q_ASSERT( begin >= 0 );
251 if ( i == vals.count() - 1 ) {
252 d->intervals << ImapInterval( begin, begin );
253 break;
254 }
255 do {
256 ++i;
257 Q_ASSERT( vals[i] >= 0 );
258 if ( vals[i] != ( vals[i - 1] + 1 ) ) {
259 --i;
260 break;
261 }
262 } while ( i < vals.count() - 1 );
263 d->intervals << ImapInterval( begin, vals[i] );
264 }
265}
266
267void ImapSet::add(const ImapInterval & interval)
268{
269 d->intervals << interval;
270}
271
272QByteArray ImapSet::toImapSequenceSet() const
273{
274 QList<QByteArray> rv;
275 foreach ( const ImapInterval &interval, d->intervals ) {
276 rv << interval.toImapSequence();
277 }
278
279 QByteArray result;
280
281 if ( !rv.isEmpty() ) {
282 result = rv.first();
283 QList<QByteArray>::ConstIterator it = rv.constBegin();
284 ++it;
285 for ( ; it != rv.constEnd(); ++it ) {
286 result += ',' + ( *it );
287 }
288 }
289
290 return result;
291}
292
293ImapSet ImapSet::fromImapSequenceSet( const QByteArray &sequence )
294{
295 ImapSet result;
296
297 QList<QByteArray> intervals = sequence.split( ',' );
298
299 foreach ( const QByteArray &interval, intervals ) {
300 if ( !interval.isEmpty() ) {
301 result.add( ImapInterval::fromImapSequence( interval ) );
302 }
303 }
304
305 return result;
306}
307
308ImapInterval::List ImapSet::intervals() const
309{
310 return d->intervals;
311}
312
313bool ImapSet::isEmpty() const
314{
315 return d->intervals.isEmpty();
316}
317
318QDebug& operator<<( QDebug &d, const ImapInterval &interval )
319{
320 d << interval.toImapSequence();
321 return d;
322}
323
324QDebug& operator<<( QDebug &d, const ImapSet &set )
325{
326 d << set.toImapSequenceSet();
327 return d;
328}
329