]> err.no Git - sope/blob - sope-mime/NGImap4/NGImap4DataSource.m
synced with latest additions and bumped framework versions
[sope] / sope-mime / NGImap4 / NGImap4DataSource.m
1 /*
2   Copyright (C) 2000-2005 SKYRIX Software AG
3
4   This file is part of SOPE.
5
6   SOPE is free software; you can redistribute it and/or modify it under
7   the terms of the GNU Lesser General Public License as published by the
8   Free Software Foundation; either version 2, or (at your option) any
9   later version.
10
11   SOPE is distributed in the hope that it will be useful, but WITHOUT ANY
12   WARRANTY; without even the implied warranty of MERCHANTABILITY or
13   FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
14   License for more details.
15
16   You should have received a copy of the GNU Lesser General Public
17   License along with SOPE; see the file COPYING.  If not, write to the
18   Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
19   02111-1307, USA.
20 */
21
22 #include "NGImap4DataSource.h"
23 #include <NGStreams/NGSocketExceptions.h>
24 #include "imCommon.h"
25
26 @interface NGImap4DataSource(PrivateMethodes)
27 - (NSArray *)fetchMessages;
28 @end
29
30 @interface EOQualifier(IMAPAdditions)
31 - (BOOL)isImap4UnseenQualifier;
32 @end
33
34 @implementation NGImap4DataSource
35
36 static BOOL profileDS = NO;
37
38 + (void)initialize {
39   NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
40   
41   if ((profileDS = [ud boolForKey:@"ProfileImap4DataSource"]))
42     NSLog(@"NGImap4DataSource: Profiling enabled!");
43 }
44
45 - (NSNotificationCenter *)notificationCenter {
46   static NSNotificationCenter *nc = nil;
47   if (nc == nil) nc = [[NSNotificationCenter defaultCenter] retain];
48   return nc;
49 }
50
51 - (id)init {
52   if ((self = [super init])) {
53     NSNotificationCenter *nc = [self notificationCenter];
54     
55     [nc addObserver:self
56         selector:@selector(mailsWereDeleted:)
57         name:@"LSWImapMailWasDeleted"
58         object:nil];
59
60     [nc addObserver:self
61         selector:@selector(folderWasMoved:)
62         name:@"LSWImapMailFolderWasDeleted"
63         object:nil];
64     
65     [nc addObserver:self
66         selector:@selector(flagsWereChanged:)
67         name:@"LSWImapMailFlagsChanged"
68         object:nil];
69   }
70   return self;
71 }
72 - (id)initWithFolder:(NGImap4Folder *)_folder {
73   if ((self = [self init])) {
74     [self setFolder:_folder];
75   }
76   return self;
77 }
78
79 - (void)dealloc {
80   [[self notificationCenter] removeObserver:self];
81   [self->folder   release];
82   [self->fspec    release];
83   [self->messages release];
84   [self->oldUnseenMessages release];
85   [super dealloc];
86 }
87
88 /* operations */
89
90 - (void)folderWasMoved:(id)_obj {
91   [self->folder   release]; self->folder   = nil;
92   [self->messages release]; self->messages = nil;
93   [self->oldUnseenMessages release]; self->oldUnseenMessages = nil;
94 }
95
96 - (void)mailsWereDeleted:(id)_obj {
97   [self->messages          release]; self->messages          = nil;
98   [self->oldUnseenMessages release]; self->oldUnseenMessages = nil;
99 }
100
101 - (void)flagsWereChanged:(id)_obj {
102   [self postDataSourceChangedNotification];
103 }
104
105 - (NSArray *)fetchObjects {
106   NSAutoreleasePool *pool;
107   NSArray *tmp;
108   
109   if (self->messages) {
110     if (profileDS) [self logWithFormat:@"fetchObjects: already fetched."];
111     return self->messages;
112   }
113     
114   pool = [[NSAutoreleasePool alloc] init];
115   {  
116     if (profileDS) [self logWithFormat:@"fetchObjects: fetch ..."];
117     
118     tmp = (self->folder) ? [self fetchMessages] : [NSArray array];
119     
120     if (profileDS) [self logWithFormat:@"fetchObjects:   done ..."];
121     ASSIGN(self->messages, tmp);
122   }
123   [pool release];
124   if (profileDS) [self logWithFormat:@"fetchObjects:   pool released."];
125   
126   return self->messages;
127 }
128
129 - (void)clear {
130   if (profileDS) [self logWithFormat:@"clear: do ..."];
131   [self->messages release];
132   self->messages = nil;
133   if (profileDS) [self logWithFormat:@"clear: done."];
134 }
135
136 - (void)setFolder:(NGImap4Folder *)_folder {
137   ASSIGN(self->folder, _folder);
138   
139   [self->messages          release]; self->messages          = nil;
140   [self->oldUnseenMessages release]; self->oldUnseenMessages = nil;
141   
142   [self postDataSourceChangedNotification];
143 }
144 - (NGImap4Folder *)folder {
145   return self->folder;
146 }
147
148 - (void)setFetchSpecification:(EOFetchSpecification *)_fetchSpec {
149   if ([_fetchSpec isEqual:self->fspec]) return;
150   
151   ASSIGN(self->fspec, _fetchSpec);
152   [self->messages release]; self->messages = nil;
153   [self postDataSourceChangedNotification];
154 }
155 - (EOFetchSpecification *)fetchSpecification {
156   return self->fspec;
157 }
158
159 - (int)oldExists {
160   return self->oldExists;
161 }
162 - (int)oldUnseen {
163   return self->oldUnseen;
164 }
165
166 /* private methodes */
167
168 - (NSException *)handleImapException:(NSException *)_exception {
169   if ([_exception isKindOfClass:[NGImap4ResponseException class]]) {
170     NSDictionary *record;
171     NSString *str;
172     
173     record = [[_exception userInfo] objectForKey:@"RawResponse"];
174     record = [record objectForKey:@"ResponseResult"];
175     str    = [record objectForKey:@"description"];
176     fprintf(stderr, "%s", [str cString]);
177   }    
178   else if ([_exception isKindOfClass:[NGIOException class]]) {
179     fprintf(stderr, "%s", [[_exception reason] cString]);
180   }
181   else if ([_exception isKindOfClass:[NGImap4Exception class]]) {
182     fprintf(stderr, "%s", [[_exception description] cString]);
183   }
184   else {
185     fprintf(stderr, "\n");
186     return _exception;
187   }
188   fprintf(stderr, "\n");
189   return nil;
190 }
191
192 - (NSArray *)_processUnseen:(NSArray *)result {
193   if (profileDS) [self logWithFormat:@"process unseen ..."];
194     
195   if (self->oldUnseenMessages) { // this implies, the folder hasn't changed
196       NSMutableSet *set = nil;
197       
198       set = [[NSMutableSet alloc] initWithArray:result];
199       [set addObjectsFromArray:self->oldUnseenMessages];
200       result = [[[set allObjects] retain] autorelease];
201       [set release];
202   }
203   [self->oldUnseenMessages release]; self->oldUnseenMessages = nil;
204   ASSIGN(self->oldUnseenMessages, result);
205     
206   if (profileDS) [self logWithFormat:@"process unseen: done."];
207   return result;
208 }
209 - (NSArray *)_sortMessages:(NSArray *)result {
210   NSArray *sortOrderings;
211
212   if ((sortOrderings = [[self fetchSpecification] sortOrderings]) == nil)
213     return result;
214   
215   if (profileDS) [self logWithFormat:@"sort messages ..."];
216   result = [result sortedArrayUsingKeyOrderArray:sortOrderings];
217   if (profileDS) [self logWithFormat:@"sort messages: done."];
218   return result;
219 }
220
221 - (NSArray *)fetchMessages {
222   EOQualifier *qualifier;
223   NSArray     *result  = nil;
224
225   if (profileDS) [self logWithFormat:@"fetchMessages: fetch ..."];
226   
227   qualifier = [[self fetchSpecification] qualifier];
228   
229   NS_DURING {
230     if (![qualifier isImap4UnseenQualifier]) {
231       [self->oldUnseenMessages release];
232       self->oldUnseenMessages = nil;
233     }
234     
235     if (profileDS) [self logWithFormat:@"fetchMessages:   exists&unseen ..."];
236     self->oldExists = [self->folder exists];
237     self->oldUnseen = [self->folder unseen];
238     
239     if (profileDS) [self logWithFormat:@"fetchMessages:   messages ..."];
240     result = (qualifier == nil)
241       ? [self->folder messages]
242       : [self->folder messagesForQualifier:qualifier];
243     if (profileDS) [self logWithFormat:@"fetchMessages:   messages done ..."];
244   }
245   NS_HANDLER {
246     [[self handleImapException:localException] raise];
247     result = [NSArray array];
248   }
249   NS_ENDHANDLER;
250   
251   if (profileDS) [self logWithFormat:@"fetchMessages:   ex handler done ..."];
252   
253   if ([qualifier isImap4UnseenQualifier])
254     result = [self _processUnseen:result];
255   
256   result = [self _sortMessages:result];
257   if (profileDS) [self logWithFormat:@"fetchMessages: done."];
258   return result;
259 }
260
261 @end /* NGImap4DataSource */