File: MAPIStoreDBFolder.m

package info (click to toggle)
sogo 2.2.9%2Bgit20141017-1
  • links: PTS, VCS
  • area: main
  • in suites: jessie-kfreebsd
  • size: 43,812 kB
  • sloc: objc: 115,592; python: 5,696; sh: 1,380; perl: 861; makefile: 240; xml: 114; sql: 53; php: 43
file content (372 lines) | stat: -rw-r--r-- 11,693 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
/* MAPIStoreDBFolder.m - this file is part of SOGo
 *
 * Copyright (C) 2011-2012 Inverse inc
 *
 * Author: Wolfgang Sourdeau <wsourdeau@inverse.ca>
 *
 * This file is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 3, or (at your option)
 * any later version.
 *
 * This file is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; see the file COPYING.  If not, write to
 * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA 02111-1307, USA.
 */

#include <inttypes.h>

#import <Foundation/NSArray.h>
#import <Foundation/NSCalendarDate.h>
#import <Foundation/NSDictionary.h>
#import <Foundation/NSException.h>
#import <Foundation/NSString.h>
#import <Foundation/NSURL.h>
#import <NGExtensions/NSObject+Logs.h>
#import <EOControl/EOQualifier.h>
#import <SOGo/SOGoFolder.h>
#import <SOGo/SOGoUser.h>
#import <SOGo/EOQualifier+SOGoCacheObject.h>
#import "MAPIStoreContext.h"
#import "MAPIStoreDBFolderTable.h"
#import "MAPIStoreDBMessage.h"
#import "MAPIStoreDBMessageTable.h"
#import "MAPIStoreMapping.h"
#import "MAPIStoreTypes.h"
#import "MAPIStoreUserContext.h"
#import <SOGo/SOGoCacheGCSFolder.h>
#import "SOGoMAPIDBMessage.h"

#import "MAPIStoreDBFolder.h"

#undef DEBUG
#include <mapistore/mapistore.h>
#include <mapistore/mapistore_errors.h>

static Class EOKeyValueQualifierK, SOGoCacheGCSFolderK, MAPIStoreDBFolderK;

static NSString *MAPIStoreRightReadItems = @"RightsReadItems";
static NSString *MAPIStoreRightCreateItems = @"RightsCreateItems";
static NSString *MAPIStoreRightEditOwn = @"RightsEditOwn";
static NSString *MAPIStoreRightEditAll = @"RightsEditAll";
static NSString *MAPIStoreRightDeleteOwn = @"RightsDeleteOwn";
static NSString *MAPIStoreRightDeleteAll = @"RightsDeleteAll";
static NSString *MAPIStoreRightCreateSubfolders = @"RightsCreateSubfolders";
static NSString *MAPIStoreRightFolderOwner = @"RightsFolderOwner";
static NSString *MAPIStoreRightFolderContact = @"RightsFolderContact";

@implementation MAPIStoreDBFolder

+ (void) initialize
{
  EOKeyValueQualifierK = [EOKeyValueQualifier class];
  SOGoCacheGCSFolderK = [SOGoCacheGCSFolder class];
  MAPIStoreDBFolderK = [MAPIStoreDBFolder class];
}

- (void) setupAuxiliaryObjects
{
  [super setupAuxiliaryObjects];
  ASSIGN (sogoObject, dbFolder);
}

- (MAPIStoreMessageTable *) messageTable
{
  return [MAPIStoreDBMessageTable tableForContainer: self];
}

- (MAPIStoreFolderTable *) folderTable
{
  return [MAPIStoreDBFolderTable tableForContainer: self];
}

- (enum mapistore_error) createFolder: (struct SRow *) aRow
                              withFID: (uint64_t) newFID
                               andKey: (NSString **) newKeyP
{
  enum mapistore_error rc;
  NSString *folderName, *nameInContainer;
  SOGoCacheGCSFolder *newFolder;
  struct SPropValue *value;

  value = get_SPropValue_SRow (aRow, PidTagDisplayName);
  if (value)
    folderName = [NSString stringWithUTF8String: value->value.lpszW];
  else
    {
      value = get_SPropValue_SRow (aRow, PidTagDisplayName_string8);
      if (value)
        folderName = [NSString stringWithUTF8String: value->value.lpszA];
      else
        folderName = nil;
    }

  if (folderName)
    {
      nameInContainer = [NSString stringWithFormat: @"0x%.16"PRIx64,
                                  (unsigned long long) newFID];
      newFolder = [SOGoCacheGCSFolderK objectWithName: nameInContainer
                                        inContainer: sogoObject];
      [newFolder reloadIfNeeded];
      [[newFolder properties] setObject: folderName
                                 forKey: MAPIPropertyKey (PidTagDisplayName)];
      [newFolder save];
      *newKeyP = nameInContainer;
      rc = MAPISTORE_SUCCESS;
    }
  else
    rc = MAPISTORE_ERR_INVALID_PARAMETER;

  return rc;
}

- (enum mapistore_error) moveCopyToFolder: (MAPIStoreFolder *) targetFolder
                              withNewName: (NSString *) newFolderName
                                   isMove: (BOOL) isMove
                              isRecursive: (BOOL) isRecursive
                                 inMemCtx: (TALLOC_CTX *) memCtx
{
  enum mapistore_error rc;
  NSString *path, *pathComponent, *targetPath, *newPath;
  NSString *newURL;
  MAPIStoreMapping *mapping;
  NSRange slashRange;

  if (isMove && [targetFolder isKindOfClass: MAPIStoreDBFolderK])
    {
      path = [sogoObject path];
      slashRange = [path rangeOfString: @"/" options: NSBackwardsSearch];
      if (slashRange.location == NSNotFound)
        [NSException raise: @"MAPIStoreIOException"
                    format: @"db folder path must start with a '/'"];

      pathComponent = [path substringFromIndex: slashRange.location + 1];
      targetPath = [[targetFolder sogoObject] path];
      newPath = [NSString stringWithFormat: @"%@/%@",
                          targetPath, pathComponent];
      [dbFolder changePathTo: newPath];
      
      mapping = [self mapping];
      newURL = [NSString stringWithFormat: @"%@%@/",
                         [targetFolder url], pathComponent];
      [mapping updateID: [self objectId]
                withURL: newURL];

      [targetFolder cleanupCaches];

      rc = MAPISTORE_SUCCESS;
    }
  else
    rc = [super moveCopyToFolder: targetFolder withNewName: newFolderName
                          isMove: isMove
                     isRecursive: isRecursive
                        inMemCtx: memCtx];

  return rc;
}

- (MAPIStoreMessage *) createMessage
{
  MAPIStoreMessage *newMessage;
  SOGoMAPIDBMessage *fsObject;
  NSString *newKey;

  newKey = [NSString stringWithFormat: @"%@.plist",
                     [SOGoObject globallyUniqueObjectId]];
  fsObject = [SOGoMAPIDBMessage objectWithName: newKey
                                   inContainer: sogoObject];
  [fsObject setObjectType: MAPIMessageCacheObject];
  [fsObject reloadIfNeeded];
  newMessage = [MAPIStoreDBMessage mapiStoreObjectWithSOGoObject: fsObject
                                                     inContainer: self];

  return newMessage;
}

- (NSArray *) messageKeysMatchingQualifier: (EOQualifier *) qualifier
                          andSortOrderings: (NSArray *) sortOrderings
{
  NSArray *keys;
  SOGoUser *ownerUser;

  ownerUser = [[self userContext] sogoUser];
  if ([[context activeUser] isEqual: ownerUser]
      || [self subscriberCanReadMessages])
    keys = [(SOGoCacheGCSFolder *) sogoObject childKeysOfType: MAPIMessageCacheObject
                                             includeDeleted: NO
                                          matchingQualifier: qualifier
                                           andSortOrderings: sortOrderings];
  else
    keys = [NSArray array];

  return keys;
}

- (NSArray *) folderKeysMatchingQualifier: (EOQualifier *) qualifier
                         andSortOrderings: (NSArray *) sortOrderings
{
  return [dbFolder childKeysOfType: MAPIFolderCacheObject
                    includeDeleted: NO
                 matchingQualifier: qualifier
                  andSortOrderings: sortOrderings];
}

/* TODO: now that we are DB-based, this method can easily be implemented

- (NSArray *) getDeletedKeysFromChangeNumber: (uint64_t) changeNum
                                       andCN: (NSNumber **) cnNbrs
                                 inTableType: (enum mapistore_table_type) tableType
{
}
*/

- (NSDate *) lastMessageModificationTime
{
  NSUInteger count, max;
  NSDate *date, *fileDate;
  MAPIStoreDBMessage *msg;
  NSArray *messageKeys;

  messageKeys = [self messageKeys];

  date = [NSCalendarDate date];
  //[self logWithFormat: @"current date: %@", date];

  max = [messageKeys count];
  for (count = 0; count < max; count++)
    {
      msg = [self lookupMessage: [messageKeys objectAtIndex: count]];
      fileDate = [msg lastModificationTime];
      if ([date laterDate: fileDate] == fileDate)
        {
          //[self logWithFormat: @"current date: %@", date];
          
          date = fileDate;
        }
    }

  return date;
}

- (SOGoFolder *) aclFolder
{
  return sogoObject;
}

- (NSArray *) rolesForExchangeRights: (uint32_t) rights
{
  NSMutableArray *roles;

  roles = [NSMutableArray arrayWithCapacity: 9];
  if (rights & RightsReadItems)
    [roles addObject: MAPIStoreRightReadItems];
  if (rights & RightsCreateItems)
    [roles addObject: MAPIStoreRightCreateItems];
  if (rights & RightsEditOwn)
    [roles addObject: MAPIStoreRightEditOwn];
  if (rights & RightsDeleteOwn)
    [roles addObject: MAPIStoreRightDeleteOwn];
  if (rights & RightsEditAll)
    [roles addObject: MAPIStoreRightEditAll];
  if (rights & RightsDeleteAll)
    [roles addObject: MAPIStoreRightDeleteAll];
  if (rights & RightsCreateSubfolders)
    [roles addObject: MAPIStoreRightCreateSubfolders];
  if (rights & RightsFolderOwner)
    [roles addObject: MAPIStoreRightFolderOwner];
  if (rights & RightsFolderContact)
    [roles addObject: MAPIStoreRightFolderContact];

  return roles;
}

- (uint32_t) exchangeRightsForRoles: (NSArray *) roles
{
  uint32_t rights = 0;

  if ([roles containsObject: MAPIStoreRightReadItems])
    rights |= RightsReadItems;
  if ([roles containsObject: MAPIStoreRightCreateItems])
    rights |= RightsCreateItems;
  if ([roles containsObject: MAPIStoreRightEditOwn])
    rights |= RightsEditOwn;
  if ([roles containsObject: MAPIStoreRightDeleteOwn])
    rights |= RightsDeleteOwn;
  if ([roles containsObject: MAPIStoreRightEditAll])
    rights |= RightsEditAll;
  if ([roles containsObject: MAPIStoreRightDeleteAll])
    rights |= RightsDeleteAll;
  if ([roles containsObject: MAPIStoreRightCreateSubfolders])
    rights |= RightsCreateSubfolders;
  if ([roles containsObject: MAPIStoreRightFolderOwner])
    rights |= RightsFolderOwner;
  if ([roles containsObject: MAPIStoreRightFolderContact])
    rights |= RightsFolderContact;
  if (rights != 0)
    rights |= RoleNone; /* actually "folder visible" */
 
  return rights;
}

- (BOOL) _testRoleForActiveUser: (const NSString *) role
{
  SOGoUser *activeUser;
  NSArray *roles;

  activeUser = [[self context] activeUser];

  roles = [[self aclFolder] aclsForUser: [activeUser login]];

  return [roles containsObject: role];
}

- (BOOL) subscriberCanCreateMessages
{
  return [self _testRoleForActiveUser: MAPIStoreRightCreateItems];
}

- (BOOL) subscriberCanModifyMessages
{
  return ([self _testRoleForActiveUser: MAPIStoreRightEditAll]
          || [self _testRoleForActiveUser: MAPIStoreRightEditOwn]);
}

- (BOOL) subscriberCanReadMessages
{
  NSString *displayName;

  /* when this folder is the "Freebusy Data" folder, we need to allow
     subscribed to read an open contained messages in order to enable them to
     find the "LocalFreebusy" message */
  [sogoObject reloadIfNeeded];
  
  displayName = [[sogoObject properties]
                  objectForKey: MAPIPropertyKey (PidTagDisplayName)];

  return ([displayName isEqualToString: @"Freebusy Data"]
          || [self _testRoleForActiveUser: MAPIStoreRightReadItems]);
}

- (BOOL) subscriberCanDeleteMessages
{
  return ([self _testRoleForActiveUser: MAPIStoreRightDeleteAll]
          || [self _testRoleForActiveUser: MAPIStoreRightDeleteOwn]);
}

- (BOOL) subscriberCanCreateSubFolders
{
  return [self _testRoleForActiveUser: MAPIStoreRightCreateSubfolders];
}

- (BOOL) supportsSubFolders
{
  return YES;
}

@end