2 Copyright (C) 2004-2005 SKYRIX Software AG
4 This file is part of OpenGroupware.org.
6 OGo 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
11 OGo 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.
16 You should have received a copy of the GNU Lesser General Public
17 License along with OGo; see the file COPYING. If not, write to the
18 Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
22 #import <NGCards/NGVCard.h>
23 #import <NGCards/NSArray+NGCards.h>
25 #import <NGObjWeb/SoObject.h>
27 #import <Contacts/SOGoContactObject.h>
28 #import <Contacts/SOGoContactFolder.h>
31 #import "UIxContactEditor.h"
33 @implementation UIxContactEditor
37 if ((self = [super init]))
39 snapshot = [[NSMutableDictionary alloc] initWithCapacity: 16];
55 - (void) setErrorText: (NSString *) _txt
57 ASSIGNCOPY(errorText, _txt);
60 - (NSString *) errorText
67 return [errorText length] > 0 ? YES : NO;
70 /* load/store content format */
72 - (void)_fixupSnapshot {
73 // TODO: perform sanity checking, eg build CN on demand
74 NSString *cn, *gn, *sn;
76 cn = [snapshot objectForKey:@"cn"];
77 gn = [snapshot objectForKey:@"givenName"];
78 sn = [snapshot objectForKey:@"sn"];
80 if (![sn isNotNull] || [sn length] == 0)
82 if (![cn isNotNull] || [cn length] == 0)
89 // TODO: need a better name parser here
92 r = [cn rangeOfString:@" "];
94 ? [cn substringFromIndex:(r.location + r.length)]
97 [snapshot setObject:sn forKey:@"sn"];
99 if (sn == nil && gn == nil)
106 cn = [[gn stringByAppendingString:@" "] stringByAppendingString:sn];
107 [snapshot setObject:cn forKey:@"cn"];
112 - (NSString *)_completeURIForMethod:(NSString *)_method {
113 // TODO: this is a DUP of UIxAppointmentEditor
117 uri = [[[self context] request] uri];
119 /* first: identify query parameters */
120 r = [uri rangeOfString:@"?" options:NSBackwardsSearch];
122 uri = [uri substringToIndex:r.location];
124 /* next: append trailing slash */
125 if (![uri hasSuffix:@"/"])
126 uri = [uri stringByAppendingString:@"/"];
128 /* next: append method */
129 uri = [uri stringByAppendingString:_method];
131 /* next: append query parameters */
132 return [self completeHrefForMethod:uri];
137 - (BOOL) shouldTakeValuesFromRequest: (WORequest *) _rq
138 inContext: (WOContext*) _c
143 - (void) _setSnapshotValue: (NSString *) key
144 to: (NSString *) aValue
149 [snapshot setObject: aValue forKey: key];
152 - (NSMutableDictionary *) snapshot
157 - (NSString *) _simpleValueForType: (NSString *) aType
158 inArray: (NSArray *) anArray
163 elements = [anArray cardElementsWithAttribute: @"type"
165 if ([elements count] > 0)
166 value = [[elements objectAtIndex: 0] value: 0];
173 - (void) _setupEmailFields
176 NSString *workMail, *homeMail, *prefMail, *potential;
179 elements = [card childrenWithTag: @"email"];
180 max = [elements count];
181 workMail = [self _simpleValueForType: @"work"
183 homeMail = [self _simpleValueForType: @"home"
185 prefMail = [self _simpleValueForType: @"pref"
190 potential = [[elements objectAtIndex: 0] value: 0];
193 if (homeMail && homeMail == potential && max > 1)
194 workMail = [[elements objectAtIndex: 1] value: 0];
196 workMail = potential;
198 if (!homeMail && max > 1)
200 if (workMail && workMail == potential)
201 homeMail = [[elements objectAtIndex: 1] value: 0];
203 homeMail = potential;
208 if (prefMail == workMail)
209 preferredEmail = @"work";
210 else if (prefMail == homeMail)
211 preferredEmail = @"home";
215 [self _setSnapshotValue: @"workMail" to: workMail];
216 [self _setSnapshotValue: @"homeMail" to: homeMail];
219 - (void) _setupOrgFields
221 NSArray *org, *orgServices;
229 [self _setSnapshotValue: @"workCompany" to: [org objectAtIndex: 0]];
232 aRange = NSMakeRange (1, max - 1);
233 orgServices = [org subarrayWithRange: aRange];
234 [self _setSnapshotValue: @"workService"
235 to: [orgServices componentsJoinedByString: @", "]];
240 - (NSString *) preferredEmail
242 return preferredEmail;
245 - (void) setPreferredEmail: (NSString *) aString
247 preferredEmail = aString;
250 - (void) _retrieveQueryParameter: (NSString *) queryKey
251 intoSnapshotValue: (NSString *) snapshotKey
253 NSString *queryValue;
255 queryValue = [self queryParameterForKey: queryKey];
256 if (queryValue && [queryValue length] > 0)
257 [self _setSnapshotValue: snapshotKey to: queryValue];
260 - (void) initSnapshot
262 NSArray *n, *elements;
263 CardElement *element;
272 [self _setSnapshotValue: @"sn" to: [n objectAtIndex: 0]];
274 [self _setSnapshotValue: @"givenName" to: [n objectAtIndex: 1]];
277 [self _setSnapshotValue: @"fn" to: [card fn]];
278 [self _setSnapshotValue: @"nickname" to: [card nickname]];
280 elements = [card childrenWithTag: @"tel"];
281 [self _setSnapshotValue: @"telephoneNumber"
282 to: [self _simpleValueForType: @"work" inArray: elements]];
283 [self _setSnapshotValue: @"homeTelephoneNumber"
284 to: [self _simpleValueForType: @"home" inArray: elements]];
285 [self _setSnapshotValue: @"mobile"
286 to: [self _simpleValueForType: @"cell" inArray: elements]];
287 [self _setSnapshotValue: @"facsimileTelephoneNumber"
288 to: [self _simpleValueForType: @"fax" inArray: elements]];
289 [self _setSnapshotValue: @"pager"
290 to: [self _simpleValueForType: @"pager" inArray: elements]];
292 [self _setupEmailFields];
294 elements = [card childrenWithTag: @"adr"
295 andAttribute: @"type" havingValue: @"work"];
296 if (elements && [elements count] > 0)
298 element = [elements objectAtIndex: 0];
299 [self _setSnapshotValue: @"workStreetAddress"
300 to: [element value: 2]];
301 [self _setSnapshotValue: @"workCity"
302 to: [element value: 3]];
303 [self _setSnapshotValue: @"workState"
304 to: [element value: 4]];
305 [self _setSnapshotValue: @"workPostalCode"
306 to: [element value: 5]];
307 [self _setSnapshotValue: @"workCountry"
308 to: [element value: 6]];
311 elements = [card childrenWithTag: @"adr"
312 andAttribute: @"type" havingValue: @"home"];
313 if (elements && [elements count] > 0)
315 element = [elements objectAtIndex: 0];
316 [self _setSnapshotValue: @"homeStreetAddress"
317 to: [element value: 2]];
318 [self _setSnapshotValue: @"homeCity"
319 to: [element value: 3]];
320 [self _setSnapshotValue: @"homeState"
321 to: [element value: 4]];
322 [self _setSnapshotValue: @"homePostalCode"
323 to: [element value: 5]];
324 [self _setSnapshotValue: @"homeCountry"
325 to: [element value: 6]];
328 elements = [card childrenWithTag: @"url"];
329 [self _setSnapshotValue: @"workURL"
330 to: [self _simpleValueForType: @"work" inArray: elements]];
331 [self _setSnapshotValue: @"homeURL"
332 to: [self _simpleValueForType: @"home" inArray: elements]];
333 [self _setSnapshotValue: @"calFBURL"
334 to: [[card uniqueChildWithTag: @"FBURL"] value: 0]];
336 [self _setSnapshotValue: @"title" to: [card title]];
337 [self _setupOrgFields];
339 [self _setSnapshotValue: @"bday" to: [card bday]];
340 [self _setSnapshotValue: @"tz" to: [card tz]];
341 [self _setSnapshotValue: @"note" to: [card note]];
343 [self _retrieveQueryParameter: @"contactEmail"
344 intoSnapshotValue: @"workMail"];
345 [self _retrieveQueryParameter: @"contactFN"
346 intoSnapshotValue: @"fn"];
349 - (id <WOActionResults>) defaultAction
351 card = [[self clientObject] vCard];
355 return [NSException exceptionWithHTTPStatus:404 /* Not Found */
356 reason:@"could not open contact"];
361 - (NSString *) viewActionName
363 /* this is overridden in the mail based contacts UI to redirect to tb.edit */
367 - (NSString *) editActionName
369 /* this is overridden in the mail based contacts UI to redirect to tb.edit */
373 - (CardElement *) _elementWithTag: (NSString *) tag
374 ofType: (NSString *) type
377 CardElement *element;
379 elements = [card childrenWithTag: tag
380 andAttribute: @"type" havingValue: type];
381 if ([elements count] > 0)
382 element = [elements objectAtIndex: 0];
385 element = [CardElement new];
386 [element autorelease];
387 [element setTag: tag];
388 [element addType: type];
389 [card addChild: element];
395 - (void) _savePhoneValues
399 phone = [self _elementWithTag: @"tel" ofType: @"work"];
400 [phone setValue: 0 to: [snapshot objectForKey: @"telephoneNumber"]];
401 phone = [self _elementWithTag: @"tel" ofType: @"home"];
402 [phone setValue: 0 to: [snapshot objectForKey: @"homeTelephoneNumber"]];
403 phone = [self _elementWithTag: @"tel" ofType: @"cell"];
404 [phone setValue: 0 to: [snapshot objectForKey: @"mobile"]];
405 phone = [self _elementWithTag: @"tel" ofType: @"fax"];
407 to: [snapshot objectForKey: @"facsimileTelephoneNumber"]];
408 phone = [self _elementWithTag: @"tel" ofType: @"pager"];
410 to: [snapshot objectForKey: @"pager"]];
415 CardElement *workMail, *homeMail;
417 workMail = [self _elementWithTag: @"email" ofType: @"work"];
418 [workMail setValue: 0 to: [snapshot objectForKey: @"workMail"]];
419 homeMail = [self _elementWithTag: @"email" ofType: @"home"];
420 [homeMail setValue: 0 to: [snapshot objectForKey: @"homeMail"]];
423 if ([preferredEmail isEqualToString: @"work"])
424 [card setPreferred: workMail];
426 [card setPreferred: homeMail];
430 - (void) _saveSnapshot
432 CardElement *element;
434 [card setNWithFamily: [snapshot objectForKey: @"sn"]
435 given: [snapshot objectForKey: @"givenName"]
439 [card setNickname: [snapshot objectForKey: @"nickname"]];
440 [card setFn: [snapshot objectForKey: @"fn"]];
441 [card setTitle: [snapshot objectForKey: @"title"]];
442 [card setBday: [snapshot objectForKey: @"bday"]];
443 [card setNote: [snapshot objectForKey: @"note"]];
444 [card setTz: [snapshot objectForKey: @"tz"]];
446 element = [self _elementWithTag: @"adr" ofType: @"home"];
447 [element setValue: 2 to: [snapshot objectForKey: @"homeStreetAddress"]];
448 [element setValue: 3 to: [snapshot objectForKey: @"homeCity"]];
449 [element setValue: 4 to: [snapshot objectForKey: @"homeState"]];
450 [element setValue: 5 to: [snapshot objectForKey: @"homePostalCode"]];
451 [element setValue: 6 to: [snapshot objectForKey: @"homeCountry"]];
453 element = [self _elementWithTag: @"adr" ofType: @"work"];
454 [element setValue: 2 to: [snapshot objectForKey: @"workStreetAddress"]];
455 [element setValue: 3 to: [snapshot objectForKey: @"workCity"]];
456 [element setValue: 4 to: [snapshot objectForKey: @"workState"]];
457 [element setValue: 5 to: [snapshot objectForKey: @"workPostalCode"]];
458 [element setValue: 6 to: [snapshot objectForKey: @"workCountry"]];
460 element = [CardElement simpleElementWithTag: @"fburl"
461 value: [snapshot objectForKey: @"calFBURL"]];
462 [card setUniqueChild: element];
464 [self _savePhoneValues];
468 - (id <WOActionResults>) saveAction
470 id <SOGoContactObject> contact;
472 NSString *jsRefreshMethod;
474 contact = [self clientObject];
475 card = [contact vCard];
478 [self _saveSnapshot];
481 if ([[[[self context] request] formValueForKey: @"nojs"] intValue])
482 result = [self redirectToLocation: [self applicationPath]];
486 = [NSString stringWithFormat: @"refreshContacts(\"%@\")",
487 [contact nameInContainer]];
488 result = [self jsCloseWithRefreshMethod: jsRefreshMethod];
492 result = [NSException exceptionWithHTTPStatus: 400 /* Bad Request */
493 reason: @"method cannot be invoked on "
494 @"the specified object"];
501 NSString *email, *url;
503 card = [[self clientObject] vCard];
505 if ([preferredEmail isEqualToString: @"home"])
506 email = [snapshot objectForKey: @"homeMail"];
508 email = [snapshot objectForKey: @"workMail"];
511 url = [NSString stringWithFormat: @"Mail/compose?mailto=%@", email];
513 url = @"Mail/compose";
516 [self redirectToLocation: [self relativePathToUserFolderSubPath: url]];
520 // TODO: this is almost a DUP of UIxAppointmentEditor
522 This method creates a unique ID and redirects to the "edit" method on the
524 It is actually a folder method and should be defined on the folder.
526 Note: 'clientObject' is the SOGoAppointmentFolder!
527 Update: remember that there are group folders as well.
529 NSString *uri, *objectId, *nextMethod;
530 id <SOGoContactFolder> co;
532 co = [self clientObject];
533 if ([[co class] respondsToSelector: @selector (globallyUniqueObjectId)])
534 objectId = [[[self clientObject] class] globallyUniqueObjectId];
538 if ([objectId length] == 0)
539 return [NSException exceptionWithHTTPStatus:500 /* Internal Error */
540 reason:@"could not create a unique ID"];
542 nextMethod = [NSString stringWithFormat:@"../%@/%@",
543 objectId, [self editActionName]];
544 uri = [self _completeURIForMethod:nextMethod];
545 return [self redirectToLocation:uri];
548 @end /* UIxContactEditor */