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 <Foundation/NSDictionary.h>
23 #import <Foundation/NSString.h>
25 #import <NGObjWeb/NSException+HTTP.h>
26 #import <NGObjWeb/SoObject.h>
27 #import <NGObjWeb/WORequest.h>
28 #import <NGExtensions/NSNull+misc.h>
30 #import <NGCards/NGVCard.h>
31 #import <NGCards/NSArray+NGCards.h>
33 #import <Contacts/SOGoContactObject.h>
34 #import <Contacts/SOGoContactFolder.h>
36 #import "UIxContactEditor.h"
38 @implementation UIxContactEditor
42 if ((self = [super init]))
44 snapshot = [[NSMutableDictionary alloc] initWithCapacity: 16];
54 [preferredEmail release];
60 - (NSArray *) htmlMailFormatList
62 static NSArray *htmlMailFormatItems = nil;
64 if (!htmlMailFormatItems)
66 htmlMailFormatItems = [NSArray arrayWithObjects: @"FALSE", @"TRUE", nil];
67 [htmlMailFormatItems retain];
70 return htmlMailFormatItems;
73 - (NSString *) itemHtmlMailFormatText
75 return [self labelForKey:
76 [NSString stringWithFormat: @"htmlMailFormat_%@", item]];
79 - (void) setItem: (NSString *) newItem
89 /* load/store content format */
91 - (void) _fixupSnapshot
93 // TODO: perform sanity checking, eg build CN on demand
94 NSString *cn, *gn, *sn;
96 cn = [snapshot objectForKey: @"cn"];
97 gn = [snapshot objectForKey: @"givenName"];
98 sn = [snapshot objectForKey: @"sn"];
100 if (![sn isNotNull] || [sn length] == 0)
102 if (![cn isNotNull] || [cn length] == 0)
109 // TODO: need a better name parser here
112 r = [cn rangeOfString: @" "];
114 ? [cn substringFromIndex:(r.location + r.length)]
117 [snapshot setObject:sn forKey: @"sn"];
119 if (sn == nil && gn == nil)
126 cn = [[gn stringByAppendingString: @" "] stringByAppendingString:sn];
127 [snapshot setObject:cn forKey: @"cn"];
132 - (NSString *)_completeURIForMethod:(NSString *)_method {
133 // TODO: this is a DUP of UIxAppointmentEditor
137 uri = [[[self context] request] uri];
139 /* first: identify query parameters */
140 r = [uri rangeOfString: @"?" options:NSBackwardsSearch];
142 uri = [uri substringToIndex:r.location];
144 /* next: append trailing slash */
145 if (![uri hasSuffix: @"/"])
146 uri = [uri stringByAppendingString: @"/"];
148 /* next: append method */
149 uri = [uri stringByAppendingString:_method];
151 /* next: append query parameters */
152 return [self completeHrefForMethod:uri];
157 - (BOOL) shouldTakeValuesFromRequest: (WORequest *) _rq
158 inContext: (WOContext*) _c
163 - (void) _setSnapshotValue: (NSString *) key
164 to: (NSString *) aValue
169 [snapshot setObject: aValue forKey: key];
172 - (NSMutableDictionary *) snapshot
177 - (NSString *) _simpleValueForType: (NSString *) aType
178 inArray: (NSArray *) anArray
183 elements = [anArray cardElementsWithAttribute: @"type"
185 if ([elements count] > 0)
186 value = [[elements objectAtIndex: 0] value: 0];
193 - (void) _setupEmailFields
196 NSString *workMail, *homeMail, *prefMail, *potential;
199 elements = [card childrenWithTag: @"email"];
200 max = [elements count];
201 workMail = [self _simpleValueForType: @"work"
203 homeMail = [self _simpleValueForType: @"home"
205 prefMail = [self _simpleValueForType: @"pref"
210 potential = [[elements objectAtIndex: 0] value: 0];
213 if (homeMail && homeMail == potential && max > 1)
214 workMail = [[elements objectAtIndex: 1] value: 0];
216 workMail = potential;
218 if (!homeMail && max > 1)
220 if (workMail && workMail == potential)
221 homeMail = [[elements objectAtIndex: 1] value: 0];
223 homeMail = potential;
228 if (prefMail == workMail)
229 preferredEmail = @"work";
230 else if (prefMail == homeMail)
231 preferredEmail = @"home";
235 [self _setSnapshotValue: @"workMail" to: workMail];
236 [self _setSnapshotValue: @"homeMail" to: homeMail];
238 [self _setSnapshotValue: @"mozillaUseHtmlMail"
239 to: [[card uniqueChildWithTag: @"x-mozilla-html"] value: 0]];
242 - (void) _setupOrgFields
244 NSArray *org, *orgServices;
252 [self _setSnapshotValue: @"workCompany" to: [org objectAtIndex: 0]];
255 aRange = NSMakeRange (1, max - 1);
256 orgServices = [org subarrayWithRange: aRange];
257 [self _setSnapshotValue: @"workService"
258 to: [orgServices componentsJoinedByString: @", "]];
263 - (NSString *) preferredEmail
265 return preferredEmail;
268 - (void) setPreferredEmail: (NSString *) aString
270 preferredEmail = aString;
273 - (void) _retrieveQueryParameter: (NSString *) queryKey
274 intoSnapshotValue: (NSString *) snapshotKey
276 NSString *queryValue;
278 queryValue = [self queryParameterForKey: queryKey];
279 if (queryValue && [queryValue length] > 0)
280 [self _setSnapshotValue: snapshotKey to: queryValue];
283 - (void) initSnapshot
285 NSArray *n, *elements;
286 CardElement *element;
295 [self _setSnapshotValue: @"sn" to: [n objectAtIndex: 0]];
297 [self _setSnapshotValue: @"givenName" to: [n objectAtIndex: 1]];
300 [self _setSnapshotValue: @"fn" to: [card fn]];
301 [self _setSnapshotValue: @"nickname" to: [card nickname]];
303 elements = [card childrenWithTag: @"tel"];
304 [self _setSnapshotValue: @"telephoneNumber"
305 to: [self _simpleValueForType: @"work" inArray: elements]];
306 [self _setSnapshotValue: @"homeTelephoneNumber"
307 to: [self _simpleValueForType: @"home" inArray: elements]];
308 [self _setSnapshotValue: @"mobile"
309 to: [self _simpleValueForType: @"cell" inArray: elements]];
310 [self _setSnapshotValue: @"facsimileTelephoneNumber"
311 to: [self _simpleValueForType: @"fax" inArray: elements]];
312 [self _setSnapshotValue: @"pager"
313 to: [self _simpleValueForType: @"pager" inArray: elements]];
315 [self _setupEmailFields];
317 [self _setSnapshotValue: @"screenName"
318 to: [[card uniqueChildWithTag: @"x-aim"] value: 0]];
320 elements = [card childrenWithTag: @"adr"
321 andAttribute: @"type" havingValue: @"work"];
322 if (elements && [elements count] > 0)
324 element = [elements objectAtIndex: 0];
325 [self _setSnapshotValue: @"workStreetAddress"
326 to: [element value: 2]];
327 [self _setSnapshotValue: @"workCity"
328 to: [element value: 3]];
329 [self _setSnapshotValue: @"workState"
330 to: [element value: 4]];
331 [self _setSnapshotValue: @"workPostalCode"
332 to: [element value: 5]];
333 [self _setSnapshotValue: @"workCountry"
334 to: [element value: 6]];
337 elements = [card childrenWithTag: @"adr"
338 andAttribute: @"type" havingValue: @"home"];
339 if (elements && [elements count] > 0)
341 element = [elements objectAtIndex: 0];
342 [self _setSnapshotValue: @"homeStreetAddress"
343 to: [element value: 2]];
344 [self _setSnapshotValue: @"homeCity"
345 to: [element value: 3]];
346 [self _setSnapshotValue: @"homeState"
347 to: [element value: 4]];
348 [self _setSnapshotValue: @"homePostalCode"
349 to: [element value: 5]];
350 [self _setSnapshotValue: @"homeCountry"
351 to: [element value: 6]];
354 elements = [card childrenWithTag: @"url"];
355 [self _setSnapshotValue: @"workURL"
356 to: [self _simpleValueForType: @"work" inArray: elements]];
357 [self _setSnapshotValue: @"homeURL"
358 to: [self _simpleValueForType: @"home" inArray: elements]];
359 [self _setSnapshotValue: @"calFBURL"
360 to: [[card uniqueChildWithTag: @"FBURL"] value: 0]];
362 [self _setSnapshotValue: @"title" to: [card title]];
363 [self _setupOrgFields];
365 [self _setSnapshotValue: @"bday" to: [card bday]];
366 [self _setSnapshotValue: @"tz" to: [card tz]];
367 [self _setSnapshotValue: @"note" to: [card note]];
369 [self _retrieveQueryParameter: @"contactEmail"
370 intoSnapshotValue: @"workMail"];
371 [self _retrieveQueryParameter: @"contactFN"
372 intoSnapshotValue: @"fn"];
375 - (id <WOActionResults>) defaultAction
377 card = [[self clientObject] vCard];
381 return [NSException exceptionWithHTTPStatus:404 /* Not Found */
382 reason: @"could not open contact"];
387 - (NSString *) viewActionName
389 /* this is overridden in the mail based contacts UI to redirect to tb.edit */
393 - (NSString *) editActionName
395 /* this is overridden in the mail based contacts UI to redirect to tb.edit */
399 - (CardElement *) _elementWithTag: (NSString *) tag
400 ofType: (NSString *) type
403 CardElement *element;
405 elements = [card childrenWithTag: tag
406 andAttribute: @"type" havingValue: type];
407 if ([elements count] > 0)
408 element = [elements objectAtIndex: 0];
411 element = [CardElement new];
412 [element autorelease];
413 [element setTag: tag];
414 [element addType: type];
415 [card addChild: element];
421 - (void) _savePhoneValues
425 phone = [self _elementWithTag: @"tel" ofType: @"work"];
426 [phone setValue: 0 to: [snapshot objectForKey: @"telephoneNumber"]];
427 phone = [self _elementWithTag: @"tel" ofType: @"home"];
428 [phone setValue: 0 to: [snapshot objectForKey: @"homeTelephoneNumber"]];
429 phone = [self _elementWithTag: @"tel" ofType: @"cell"];
430 [phone setValue: 0 to: [snapshot objectForKey: @"mobile"]];
431 phone = [self _elementWithTag: @"tel" ofType: @"fax"];
433 to: [snapshot objectForKey: @"facsimileTelephoneNumber"]];
434 phone = [self _elementWithTag: @"tel" ofType: @"pager"];
436 to: [snapshot objectForKey: @"pager"]];
441 CardElement *workMail, *homeMail;
443 workMail = [self _elementWithTag: @"email" ofType: @"work"];
444 [workMail setValue: 0 to: [snapshot objectForKey: @"workMail"]];
445 homeMail = [self _elementWithTag: @"email" ofType: @"home"];
446 [homeMail setValue: 0 to: [snapshot objectForKey: @"homeMail"]];
449 if ([preferredEmail isEqualToString: @"work"])
450 [card setPreferred: workMail];
452 [card setPreferred: homeMail];
455 [[card uniqueChildWithTag: @"x-mozilla-html"]
457 to: [snapshot objectForKey: @"mozillaUseHtmlMail"]];
460 - (void) _saveSnapshot
462 CardElement *element;
465 [card setNWithFamily: [snapshot objectForKey: @"sn"]
466 given: [snapshot objectForKey: @"givenName"]
470 [card setNickname: [snapshot objectForKey: @"nickname"]];
471 [card setFn: [snapshot objectForKey: @"fn"]];
472 [card setTitle: [snapshot objectForKey: @"title"]];
473 [card setBday: [snapshot objectForKey: @"bday"]];
474 [card setNote: [snapshot objectForKey: @"note"]];
475 [card setTz: [snapshot objectForKey: @"tz"]];
477 element = [self _elementWithTag: @"adr" ofType: @"home"];
478 [element setValue: 2 to: [snapshot objectForKey: @"homeStreetAddress"]];
479 [element setValue: 3 to: [snapshot objectForKey: @"homeCity"]];
480 [element setValue: 4 to: [snapshot objectForKey: @"homeState"]];
481 [element setValue: 5 to: [snapshot objectForKey: @"homePostalCode"]];
482 [element setValue: 6 to: [snapshot objectForKey: @"homeCountry"]];
484 element = [self _elementWithTag: @"adr" ofType: @"work"];
485 [element setValue: 2 to: [snapshot objectForKey: @"workStreetAddress"]];
486 [element setValue: 3 to: [snapshot objectForKey: @"workCity"]];
487 [element setValue: 4 to: [snapshot objectForKey: @"workState"]];
488 [element setValue: 5 to: [snapshot objectForKey: @"workPostalCode"]];
489 [element setValue: 6 to: [snapshot objectForKey: @"workCountry"]];
491 element = [CardElement simpleElementWithTag: @"fburl"
492 value: [snapshot objectForKey: @"calFBURL"]];
493 [card setUniqueChild: element];
495 units = [NSArray arrayWithObject: [snapshot objectForKey: @"workService"]];
496 [card setOrg: [snapshot objectForKey: @"workCompany"]
499 [self _savePhoneValues];
501 [[self _elementWithTag: @"url" ofType: @"home"]
502 setValue: 0 to: [snapshot objectForKey: @"homeURL"]];
503 [[self _elementWithTag: @"url" ofType: @"work"]
504 setValue: 0 to: [snapshot objectForKey: @"workURL"]];
506 [[card uniqueChildWithTag: @"x-aim"]
508 to: [snapshot objectForKey: @"screenName"]];
511 - (id <WOActionResults>) saveAction
513 id <SOGoContactObject> contact;
515 NSString *jsRefreshMethod;
517 contact = [self clientObject];
518 card = [contact vCard];
521 [self _saveSnapshot];
524 if ([[[[self context] request] formValueForKey: @"nojs"] intValue])
525 result = [self redirectToLocation: [self applicationPath]];
529 = [NSString stringWithFormat: @"refreshContacts(\"%@\")",
530 [contact nameInContainer]];
531 result = [self jsCloseWithRefreshMethod: jsRefreshMethod];
535 result = [NSException exceptionWithHTTPStatus: 400 /* Bad Request */
536 reason: @"method cannot be invoked on "
537 @"the specified object"];
544 NSString *email, *cn, *url;
545 NSMutableString *address;
547 card = [[self clientObject] vCard];
549 if ([preferredEmail isEqualToString: @"home"])
550 email = [snapshot objectForKey: @"homeMail"];
552 email = [snapshot objectForKey: @"workMail"];
556 address = [NSMutableString string];
559 [address appendFormat: @"%@ <%@>", cn, email];
561 [address appendString: email];
563 url = [NSString stringWithFormat: @"Mail/compose?mailto=%@", address];
566 url = @"Mail/compose";
569 [self redirectToLocation: [self relativePathToUserFolderSubPath: url]];
574 // TODO: this is almost a DUP of UIxAppointmentEditor
576 This method creates a unique ID and redirects to the "edit" method on the
578 It is actually a folder method and should be defined on the folder.
580 Note: 'clientObject' is the SOGoAppointmentFolder!
581 Update: remember that there are group folders as well.
583 NSString *uri, *objectId, *nextMethod;
584 id <SOGoContactFolder> co;
586 co = [self clientObject];
587 if ([[co class] respondsToSelector: @selector (globallyUniqueObjectId)])
588 objectId = [[[self clientObject] class] globallyUniqueObjectId];
592 if ([objectId length] == 0)
593 return [NSException exceptionWithHTTPStatus: 500 /* Internal Error */
594 reason: @"could not create a unique ID"];
596 nextMethod = [NSString stringWithFormat: @"../%@/%@",
597 objectId, [self editActionName]];
598 uri = [self _completeURIForMethod: nextMethod];
599 return [self redirectToLocation: uri];
602 @end /* UIxContactEditor */