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];
49 [preferredEmail release];
55 - (NSArray *) htmlMailFormatList
57 static NSArray *htmlMailFormatItems = nil;
59 if (!htmlMailFormatItems)
61 htmlMailFormatItems = [NSArray arrayWithObjects: @"FALSE", @"TRUE", nil];
62 [htmlMailFormatItems retain];
65 return htmlMailFormatItems;
68 - (NSString *) itemHtmlMailFormatText
70 return [self labelForKey:
71 [NSString stringWithFormat: @"htmlMailFormat_%@", item]];
74 - (void) setItem: (NSString *) newItem
84 /* load/store content format */
86 - (void) _fixupSnapshot
88 // TODO: perform sanity checking, eg build CN on demand
89 NSString *cn, *gn, *sn;
91 cn = [snapshot objectForKey: @"cn"];
92 gn = [snapshot objectForKey: @"givenName"];
93 sn = [snapshot objectForKey: @"sn"];
95 if (![sn isNotNull] || [sn length] == 0)
97 if (![cn isNotNull] || [cn length] == 0)
104 // TODO: need a better name parser here
107 r = [cn rangeOfString: @" "];
109 ? [cn substringFromIndex:(r.location + r.length)]
112 [snapshot setObject:sn forKey: @"sn"];
114 if (sn == nil && gn == nil)
121 cn = [[gn stringByAppendingString: @" "] stringByAppendingString:sn];
122 [snapshot setObject:cn forKey: @"cn"];
127 - (NSString *)_completeURIForMethod:(NSString *)_method {
128 // TODO: this is a DUP of UIxAppointmentEditor
132 uri = [[[self context] request] uri];
134 /* first: identify query parameters */
135 r = [uri rangeOfString: @"?" options:NSBackwardsSearch];
137 uri = [uri substringToIndex:r.location];
139 /* next: append trailing slash */
140 if (![uri hasSuffix: @"/"])
141 uri = [uri stringByAppendingString: @"/"];
143 /* next: append method */
144 uri = [uri stringByAppendingString:_method];
146 /* next: append query parameters */
147 return [self completeHrefForMethod:uri];
152 - (BOOL) shouldTakeValuesFromRequest: (WORequest *) _rq
153 inContext: (WOContext*) _c
158 - (void) _setSnapshotValue: (NSString *) key
159 to: (NSString *) aValue
164 [snapshot setObject: aValue forKey: key];
167 - (NSMutableDictionary *) snapshot
172 - (NSString *) _simpleValueForType: (NSString *) aType
173 inArray: (NSArray *) anArray
178 elements = [anArray cardElementsWithAttribute: @"type"
180 if ([elements count] > 0)
181 value = [[elements objectAtIndex: 0] value: 0];
188 - (void) _setupEmailFields
191 NSString *workMail, *homeMail, *prefMail, *potential;
194 elements = [card childrenWithTag: @"email"];
195 max = [elements count];
196 workMail = [self _simpleValueForType: @"work"
198 homeMail = [self _simpleValueForType: @"home"
200 prefMail = [self _simpleValueForType: @"pref"
205 potential = [[elements objectAtIndex: 0] value: 0];
208 if (homeMail && homeMail == potential && max > 1)
209 workMail = [[elements objectAtIndex: 1] value: 0];
211 workMail = potential;
213 if (!homeMail && max > 1)
215 if (workMail && workMail == potential)
216 homeMail = [[elements objectAtIndex: 1] value: 0];
218 homeMail = potential;
223 if (prefMail == workMail)
224 preferredEmail = @"work";
225 else if (prefMail == homeMail)
226 preferredEmail = @"home";
230 [self _setSnapshotValue: @"workMail" to: workMail];
231 [self _setSnapshotValue: @"homeMail" to: homeMail];
233 [self _setSnapshotValue: @"mozillaUseHtmlMail"
234 to: [[card uniqueChildWithTag: @"x-mozilla-html"] value: 0]];
237 - (void) _setupOrgFields
239 NSArray *org, *orgServices;
247 [self _setSnapshotValue: @"workCompany" to: [org objectAtIndex: 0]];
250 aRange = NSMakeRange (1, max - 1);
251 orgServices = [org subarrayWithRange: aRange];
252 [self _setSnapshotValue: @"workService"
253 to: [orgServices componentsJoinedByString: @", "]];
258 - (NSString *) preferredEmail
260 return preferredEmail;
263 - (void) setPreferredEmail: (NSString *) aString
265 preferredEmail = aString;
268 - (void) _retrieveQueryParameter: (NSString *) queryKey
269 intoSnapshotValue: (NSString *) snapshotKey
271 NSString *queryValue;
273 queryValue = [self queryParameterForKey: queryKey];
274 if (queryValue && [queryValue length] > 0)
275 [self _setSnapshotValue: snapshotKey to: queryValue];
278 - (void) initSnapshot
280 NSArray *n, *elements;
281 CardElement *element;
290 [self _setSnapshotValue: @"sn" to: [n objectAtIndex: 0]];
292 [self _setSnapshotValue: @"givenName" to: [n objectAtIndex: 1]];
295 [self _setSnapshotValue: @"fn" to: [card fn]];
296 [self _setSnapshotValue: @"nickname" to: [card nickname]];
298 elements = [card childrenWithTag: @"tel"];
299 [self _setSnapshotValue: @"telephoneNumber"
300 to: [self _simpleValueForType: @"work" inArray: elements]];
301 [self _setSnapshotValue: @"homeTelephoneNumber"
302 to: [self _simpleValueForType: @"home" inArray: elements]];
303 [self _setSnapshotValue: @"mobile"
304 to: [self _simpleValueForType: @"cell" inArray: elements]];
305 [self _setSnapshotValue: @"facsimileTelephoneNumber"
306 to: [self _simpleValueForType: @"fax" inArray: elements]];
307 [self _setSnapshotValue: @"pager"
308 to: [self _simpleValueForType: @"pager" inArray: elements]];
310 [self _setupEmailFields];
312 [self _setSnapshotValue: @"screenName"
313 to: [[card uniqueChildWithTag: @"x-aim"] value: 0]];
315 elements = [card childrenWithTag: @"adr"
316 andAttribute: @"type" havingValue: @"work"];
317 if (elements && [elements count] > 0)
319 element = [elements objectAtIndex: 0];
320 [self _setSnapshotValue: @"workStreetAddress"
321 to: [element value: 2]];
322 [self _setSnapshotValue: @"workCity"
323 to: [element value: 3]];
324 [self _setSnapshotValue: @"workState"
325 to: [element value: 4]];
326 [self _setSnapshotValue: @"workPostalCode"
327 to: [element value: 5]];
328 [self _setSnapshotValue: @"workCountry"
329 to: [element value: 6]];
332 elements = [card childrenWithTag: @"adr"
333 andAttribute: @"type" havingValue: @"home"];
334 if (elements && [elements count] > 0)
336 element = [elements objectAtIndex: 0];
337 [self _setSnapshotValue: @"homeStreetAddress"
338 to: [element value: 2]];
339 [self _setSnapshotValue: @"homeCity"
340 to: [element value: 3]];
341 [self _setSnapshotValue: @"homeState"
342 to: [element value: 4]];
343 [self _setSnapshotValue: @"homePostalCode"
344 to: [element value: 5]];
345 [self _setSnapshotValue: @"homeCountry"
346 to: [element value: 6]];
349 elements = [card childrenWithTag: @"url"];
350 [self _setSnapshotValue: @"workURL"
351 to: [self _simpleValueForType: @"work" inArray: elements]];
352 [self _setSnapshotValue: @"homeURL"
353 to: [self _simpleValueForType: @"home" inArray: elements]];
354 [self _setSnapshotValue: @"calFBURL"
355 to: [[card uniqueChildWithTag: @"FBURL"] value: 0]];
357 [self _setSnapshotValue: @"title" to: [card title]];
358 [self _setupOrgFields];
360 [self _setSnapshotValue: @"bday" to: [card bday]];
361 [self _setSnapshotValue: @"tz" to: [card tz]];
362 [self _setSnapshotValue: @"note" to: [card note]];
364 [self _retrieveQueryParameter: @"contactEmail"
365 intoSnapshotValue: @"workMail"];
366 [self _retrieveQueryParameter: @"contactFN"
367 intoSnapshotValue: @"fn"];
370 - (id <WOActionResults>) defaultAction
372 card = [[self clientObject] vCard];
376 return [NSException exceptionWithHTTPStatus:404 /* Not Found */
377 reason: @"could not open contact"];
382 - (NSString *) viewActionName
384 /* this is overridden in the mail based contacts UI to redirect to tb.edit */
388 - (NSString *) editActionName
390 /* this is overridden in the mail based contacts UI to redirect to tb.edit */
394 - (CardElement *) _elementWithTag: (NSString *) tag
395 ofType: (NSString *) type
398 CardElement *element;
400 elements = [card childrenWithTag: tag
401 andAttribute: @"type" havingValue: type];
402 if ([elements count] > 0)
403 element = [elements objectAtIndex: 0];
406 element = [CardElement new];
407 [element autorelease];
408 [element setTag: tag];
409 [element addType: type];
410 [card addChild: element];
416 - (void) _savePhoneValues
420 phone = [self _elementWithTag: @"tel" ofType: @"work"];
421 [phone setValue: 0 to: [snapshot objectForKey: @"telephoneNumber"]];
422 phone = [self _elementWithTag: @"tel" ofType: @"home"];
423 [phone setValue: 0 to: [snapshot objectForKey: @"homeTelephoneNumber"]];
424 phone = [self _elementWithTag: @"tel" ofType: @"cell"];
425 [phone setValue: 0 to: [snapshot objectForKey: @"mobile"]];
426 phone = [self _elementWithTag: @"tel" ofType: @"fax"];
428 to: [snapshot objectForKey: @"facsimileTelephoneNumber"]];
429 phone = [self _elementWithTag: @"tel" ofType: @"pager"];
431 to: [snapshot objectForKey: @"pager"]];
436 CardElement *workMail, *homeMail;
438 workMail = [self _elementWithTag: @"email" ofType: @"work"];
439 [workMail setValue: 0 to: [snapshot objectForKey: @"workMail"]];
440 homeMail = [self _elementWithTag: @"email" ofType: @"home"];
441 [homeMail setValue: 0 to: [snapshot objectForKey: @"homeMail"]];
444 if ([preferredEmail isEqualToString: @"work"])
445 [card setPreferred: workMail];
447 [card setPreferred: homeMail];
450 [[card uniqueChildWithTag: @"x-mozilla-html"]
452 to: [snapshot objectForKey: @"mozillaUseHtmlMail"]];
455 - (void) _saveSnapshot
457 CardElement *element;
460 [card setNWithFamily: [snapshot objectForKey: @"sn"]
461 given: [snapshot objectForKey: @"givenName"]
465 [card setNickname: [snapshot objectForKey: @"nickname"]];
466 [card setFn: [snapshot objectForKey: @"fn"]];
467 [card setTitle: [snapshot objectForKey: @"title"]];
468 [card setBday: [snapshot objectForKey: @"bday"]];
469 [card setNote: [snapshot objectForKey: @"note"]];
470 [card setTz: [snapshot objectForKey: @"tz"]];
472 element = [self _elementWithTag: @"adr" ofType: @"home"];
473 [element setValue: 2 to: [snapshot objectForKey: @"homeStreetAddress"]];
474 [element setValue: 3 to: [snapshot objectForKey: @"homeCity"]];
475 [element setValue: 4 to: [snapshot objectForKey: @"homeState"]];
476 [element setValue: 5 to: [snapshot objectForKey: @"homePostalCode"]];
477 [element setValue: 6 to: [snapshot objectForKey: @"homeCountry"]];
479 element = [self _elementWithTag: @"adr" ofType: @"work"];
480 [element setValue: 2 to: [snapshot objectForKey: @"workStreetAddress"]];
481 [element setValue: 3 to: [snapshot objectForKey: @"workCity"]];
482 [element setValue: 4 to: [snapshot objectForKey: @"workState"]];
483 [element setValue: 5 to: [snapshot objectForKey: @"workPostalCode"]];
484 [element setValue: 6 to: [snapshot objectForKey: @"workCountry"]];
486 element = [CardElement simpleElementWithTag: @"fburl"
487 value: [snapshot objectForKey: @"calFBURL"]];
488 [card setUniqueChild: element];
490 units = [NSArray arrayWithObject: [snapshot objectForKey: @"workService"]];
491 [card setOrg: [snapshot objectForKey: @"workCompany"]
494 [self _savePhoneValues];
496 [[self _elementWithTag: @"url" ofType: @"home"]
497 setValue: 0 to: [snapshot objectForKey: @"homeURL"]];
498 [[self _elementWithTag: @"url" ofType: @"work"]
499 setValue: 0 to: [snapshot objectForKey: @"workURL"]];
501 [[card uniqueChildWithTag: @"x-aim"]
503 to: [snapshot objectForKey: @"screenName"]];
506 - (id <WOActionResults>) saveAction
508 id <SOGoContactObject> contact;
510 NSString *jsRefreshMethod;
512 contact = [self clientObject];
513 card = [contact vCard];
516 [self _saveSnapshot];
519 if ([[[[self context] request] formValueForKey: @"nojs"] intValue])
520 result = [self redirectToLocation: [self applicationPath]];
524 = [NSString stringWithFormat: @"refreshContacts(\"%@\")",
525 [contact nameInContainer]];
526 result = [self jsCloseWithRefreshMethod: jsRefreshMethod];
530 result = [NSException exceptionWithHTTPStatus: 400 /* Bad Request */
531 reason: @"method cannot be invoked on "
532 @"the specified object"];
539 NSString *email, *url;
541 card = [[self clientObject] vCard];
543 if ([preferredEmail isEqualToString: @"home"])
544 email = [snapshot objectForKey: @"homeMail"];
546 email = [snapshot objectForKey: @"workMail"];
549 url = [NSString stringWithFormat: @"Mail/compose?mailto=%@", email];
551 url = @"Mail/compose";
554 [self redirectToLocation: [self relativePathToUserFolderSubPath: url]];
559 // TODO: this is almost a DUP of UIxAppointmentEditor
561 This method creates a unique ID and redirects to the "edit" method on the
563 It is actually a folder method and should be defined on the folder.
565 Note: 'clientObject' is the SOGoAppointmentFolder!
566 Update: remember that there are group folders as well.
568 NSString *uri, *objectId, *nextMethod;
569 id <SOGoContactFolder> co;
571 co = [self clientObject];
572 if ([[co class] respondsToSelector: @selector (globallyUniqueObjectId)])
573 objectId = [[[self clientObject] class] globallyUniqueObjectId];
577 if ([objectId length] == 0)
578 return [NSException exceptionWithHTTPStatus:500 /* Internal Error */
579 reason: @"could not create a unique ID"];
581 nextMethod = [NSString stringWithFormat: @"../%@/%@",
582 objectId, [self editActionName]];
583 uri = [self _completeURIForMethod:nextMethod];
584 return [self redirectToLocation:uri];
587 @end /* UIxContactEditor */