]> err.no Git - scalable-opengroupware.org/blob - UI/Contacts/UIxContactEditorBase.m
80ff0096c33015498f421b238422e44b88471960
[scalable-opengroupware.org] / UI / Contacts / UIxContactEditorBase.m
1 /*
2   Copyright (C) 2004-2005 SKYRIX Software AG
3
4   This file is part of OpenGroupware.org.
5
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
9   later version.
10
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.
15
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
19   02111-1307, USA.
20 */
21
22 #include "UIxContactEditorBase.h"
23 #include <Contacts/SOGoContactObject.h>
24 #include <Contacts/SOGoContactFolder.h>
25 #include "common.h"
26
27 @implementation UIxContactEditorBase
28
29 - (id)init {
30   if ((self = [super init])) {
31     self->snapshot = [[NSMutableDictionary alloc] initWithCapacity:16];
32   }
33   return self;
34 }
35
36 - (void)dealloc {
37   [self->snapshot      release];
38   [self->anaisCN      release];
39   [self->errorText     release];
40   [self->contentString release];
41   [super dealloc];
42 }
43
44 /* accessors */
45
46 - (void)setContentString:(NSString *)_cstr {
47   ASSIGNCOPY(self->contentString, _cstr);
48 }
49 - (NSString *)contentString {
50   return self->contentString;
51 }
52
53 - (NSString *)contentStringTemplate {
54   return @"{}"; /* empty property list */
55 }
56
57 - (NSMutableDictionary *)snapshot {
58   return self->snapshot;
59 }
60
61 - (void)setErrorText:(NSString *)_txt {
62   ASSIGNCOPY(self->errorText, _txt);
63 }
64 - (NSString *)errorText {
65   return self->errorText;
66 }
67
68 - (BOOL)hasErrorText {
69   return [self->errorText length] > 0 ? YES : NO;
70 }
71
72
73 - (void)setAnaisCN:(NSString *)_txt {
74   ASSIGNCOPY(self->anaisCN, _txt);
75 }
76 - (NSString *)anaisCN {
77   return self->anaisCN;
78 }
79
80
81 /* load/store content format */
82
83 - (void)loadValuesFromContentString:(NSString *)_s {
84   NSDictionary *plist;
85
86   if ([_s hasPrefix:@"BEGIN:VCARD"]) {
87     // TODO: load vCard values
88     [self errorWithFormat:@"Editing of vCard's is not yet supported!"];
89     return;
90   }
91   
92   if ((plist = [_s propertyList]) == nil) {
93     [self errorWithFormat:@"could not parse content string!"];
94     return;
95   }
96   
97   [self->snapshot removeAllObjects];
98   [self->snapshot addEntriesFromDictionary:plist];
99 }
100
101 - (void)_fixupSnapshot {
102   // TODO: perform sanity checking, eg build CN on demand
103   NSString *cn, *gn, *sn;
104   
105   cn = [self->snapshot objectForKey:@"cn"];
106   gn = [self->snapshot objectForKey:@"givenName"];
107   sn = [self->snapshot objectForKey:@"sn"];
108   
109   if (![sn isNotNull] || [sn length] == 0)
110     sn = nil;
111   if (![cn isNotNull] || [cn length] == 0)
112     cn = nil;
113   
114   if (sn == nil) {
115     if (cn == nil)
116       sn = @"[noname]";
117     else {
118       // TODO: need a better name parser here
119       NSRange r;
120       
121       r = [cn rangeOfString:@" "];
122       sn = (r.length > 0)
123         ? [cn substringFromIndex:(r.location + r.length)]
124         : cn;
125     }
126     [self->snapshot setObject:sn forKey:@"sn"];
127   }
128   if ([self->anaisCN length] > 0 )
129     cn = self->anaisCN;
130   else if (sn == nil && gn == nil)
131     cn = @"[noname]";
132   else if (sn == nil)
133     cn = gn;
134   else if (gn == nil)
135     cn = sn;
136   else
137     cn = [[gn stringByAppendingString:@" "] stringByAppendingString:sn];
138   [self->snapshot setObject:cn forKey:@"cn"];
139 }
140
141 - (void)saveValuesIntoRecord:(NSMutableDictionary *)_record {
142   [self _fixupSnapshot];
143   [_record addEntriesFromDictionary:[self snapshot]];
144 }
145
146 /* helper */
147
148 - (NSString *)_completeURIForMethod:(NSString *)_method {
149   // TODO: this is a DUP of UIxAppointmentEditor
150   NSString *uri;
151   NSRange r;
152     
153   uri = [[[self context] request] uri];
154     
155   /* first: identify query parameters */
156   r = [uri rangeOfString:@"?" options:NSBackwardsSearch];
157   if (r.length > 0)
158     uri = [uri substringToIndex:r.location];
159     
160   /* next: append trailing slash */
161   if (![uri hasSuffix:@"/"])
162     uri = [uri stringByAppendingString:@"/"];
163   
164   /* next: append method */
165   uri = [uri stringByAppendingString:_method];
166     
167   /* next: append query parameters */
168   return [self completeHrefForMethod:uri];
169 }
170
171 /* actions */
172
173 - (BOOL)shouldTakeValuesFromRequest:(WORequest *)_rq inContext:(WOContext*)_c{
174   return YES;
175 }
176
177 - (id<WOActionResults>)defaultAction {
178   // TODO: very similiar to apt-editor (apt editor would need to use std names
179   NSString *c;
180   
181   /* load iCalendar file */
182   
183   c = [[self clientObject] contentAsString];
184   if ([c length] == 0) /* a new contact */
185     c = [self contentStringTemplate];
186   
187   [self setContentString:c];
188   [self loadValuesFromContentString:c];
189   
190   return self;
191 }
192
193 - (BOOL)isWriteableClientObject {
194   return [[self clientObject] 
195                 respondsToSelector:@selector(saveContentString:)];
196 }
197
198 - (NSString *)viewActionName {
199   /* this is overridden in the mail based contacts UI to redirect to tb.edit */
200   return @"";
201 }
202 - (NSString *)editActionName {
203   /* this is overridden in the mail based contacts UI to redirect to tb.edit */
204   return @"edit";
205 }
206
207 - (id)saveAction {
208   NSException *ex;
209   NSString *recstr, *uri;
210   id record;
211   
212   if (![self isWriteableClientObject]) {
213     return [NSException exceptionWithHTTPStatus:400 /* Bad Request */
214                         reason:@"method cannot be invoked on "
215                                @"the specified object"];
216   }
217   
218   if ((record = [self contentString]) == nil) {
219     [self setErrorText:@"Missing object content!"]; // localize
220     return self;
221   }
222   record = [[[record propertyList] mutableCopy] autorelease];
223   if (record == nil) {
224     [self setErrorText:@"Invalid property list data ..."]; // localize
225     return self;
226   }
227   
228   [self saveValuesIntoRecord:record];
229   
230   // TODO: directly hacking the content, hm, not so nice or reasonable?
231   recstr = [record description]; // make plist
232   ex = [[self clientObject] saveContentString:recstr];
233   if (ex != nil) {
234     [self setErrorText:[ex reason]];
235     return self;
236   }
237   
238   uri = ([(uri = [self viewActionName]) length] > 0)
239     ? [self viewActionName] : @"..";
240   uri = [self _completeURIForMethod:uri];
241   return [self redirectToLocation:uri];
242 }
243
244 - (id)testAction {
245   [self logWithFormat:@"test ..."];
246   return self;
247 }
248
249 - (id)newAction {
250   // TODO: this is almost a DUP of UIxAppointmentEditor
251   /*
252     This method creates a unique ID and redirects to the "edit" method on the
253     new ID.
254     It is actually a folder method and should be defined on the folder.
255     
256     Note: 'clientObject' is the SOGoAppointmentFolder!
257           Update: remember that there are group folders as well.
258   */
259   NSString *uri, *objectId, *nextMethod;
260   
261   objectId = [NSClassFromString(@"SOGoContactFolder") globallyUniqueObjectId];
262   if ([objectId length] == 0) {
263     return [NSException exceptionWithHTTPStatus:500 /* Internal Error */
264                         reason:@"could not create a unique ID"];
265   }
266   
267   nextMethod = [NSString stringWithFormat:@"../%@/%@", 
268                            objectId, [self editActionName]];
269   uri = [self _completeURIForMethod:nextMethod];
270   return [self redirectToLocation:uri];
271 }
272
273 @end /* UIxContactEditorBase */