+2008-03-07 Wolfgang Sourdeau <wsourdeau@inverse.ca>
+
+ * OGoContentStore/OCSContactFieldExtractor.m
+ ([OCSContactFieldExtractor -extractQuickFieldsFromVList:vList]):
+ new method to handle extraction of quick information from the
+ VLIST components. I.e.: the display name of the card.
+
+ * SoObjects/SOGo/SOGoFolder.m ([SOGoFolder
+ -isValidContentName:name]): moved method from
+ SOGoAppointmentFolder's isValidAppointmentName.
+
+ * SoObjects/Contacts/SOGoContactGCSFolder.m ([SOGoContactGCSFolder -objectClassForContent:content])
+ ([SOGoContactGCSFolder -deduceObjectForName:inContext:])
+ ([SOGoContactGCSFolder -requestNamedIsHandledLater:name])
+ ([SOGoContactGCSFolder -lookupName:inContext:acquire:]): those
+ methods were modified to match the ones in SOGoAppointmentFolder,
+ in order to manage both vcard and vlist components.
+
+ * SoObjects/Contacts/SOGoContactGCSList.[hm]: new class module
+ that implements the list counterpart to VCARD: VLIST.
+
+ * UI/Contacts/UIxContactEditor.m ([UIxContactEditor -saveURL]):
+ new accessor that returns the url + "saveAsContact".
+ ([UIxContactEditor
+ -shouldTakeValuesFromRequest:requestinContext:context]): changed
+ method to match the one from the event and todo editor module.
+ ([UIxContactEditor -editActionName]): changed to "editAsContact".
+ ([UIxContactEditor -newAction]): changed method to match the one
+ from the event and todo editor module.
+
+ * UI/Contacts/UIxListView.m: new view module for the VLIST format
+ components.
+
+ * UI/Contacts/UIxListEditor.m: new edition module for the VLIST
+ format components.
+
+ * SoObjects/Contacts/SOGoContactGCSList.m: new controller module
+ for the VLIST format.
+
+2008-03-04 Wolfgang Sourdeau <wsourdeau@inverse.ca>
+
+ * SoObjects/SOGo/SOGoObject.m ([SOGoObject -isFolderish]): new
+ parent method, meant to be overriden.
+ ([SOGoObject -davIsCollection]): moved method from SOGoFolder up
+ to this parent class.
+
2008-02-25 Wolfgang Sourdeau <wsourdeau@inverse.ca>
* SoObjects/SOGo/SOGoGCSFolder.m ([SOGoGCSFolder
- retrieving the freebusy DAV object was causing SOGo to crash
- converted to use the gnustep-make 2 build framework
- added custom DAV methods for managing user permissions from the SOGo Integrator
+- pressing enter in the contact edition dialog will perform the creation/update operation
0.9.0-20080208 (1.0 rc5)
------------------------
#import <GDLContentStore/GCSFieldExtractor.h>
#import <NGCards/NGVCard.h>
+#import <NGCards/NGVList.h>
@interface OCSContactFieldExtractor : GCSFieldExtractor
@end
[fields setObject: [adr value: 3] forKey: @"c_l"];
value = [[vCard uniqueChildWithTag: @"X-AIM"] value: 0];
[fields setObject: value forKey: @"c_screenname"];
+ [fields setObject: @"vcard" forKey: @"c_component"];
+
+ return fields;
+}
+
+- (NSMutableDictionary *) extractQuickFieldsFromVList: (NGVList *) vList
+{
+ NSMutableDictionary *fields;
+ NSString *value;
+
+ fields = [NSMutableDictionary dictionaryWithCapacity: 1];
+
+ value = [vList fn];
+ if (value)
+ [fields setObject: value forKey: @"c_cn"];
+ [fields setObject: @"vlist" forKey: @"c_component"];
return fields;
}
{
NSMutableDictionary *fields;
NGVCard *vCard;
+ NGVList *vList;
+ NSString *upperContent;
fields = nil;
- if ([content length] > 0
- && [[content uppercaseString] hasPrefix: @"BEGIN:VCARD"])
+ if ([content length] > 0)
{
- vCard = [NGVCard parseSingleFromSource: content];
- if (vCard)
- fields = [self extractQuickFieldsFromVCard: vCard];
+ upperContent = [content uppercaseString];
+ if ([upperContent hasPrefix: @"BEGIN:VCARD"])
+ {
+ vCard = [NGVCard parseSingleFromSource: content];
+ if (vCard)
+ fields = [self extractQuickFieldsFromVCard: vCard];
+ else
+ [self errorWithFormat: @"Could not parse VCARD content."];
+ }
+ else if ([upperContent hasPrefix: @"BEGIN:VLIST"])
+ {
+ vList = [NGVList parseSingleFromSource: content];
+ if (vList)
+ fields = [self extractQuickFieldsFromVList: vList];
+ else
+ [self errorWithFormat: @"Could not parse VLIST content."];
+ }
else
- [self errorWithFormat: @"Could not parse content as a vCard."];
+ [self errorWithFormat: @"Content is unknown."];
}
else
- [self errorWithFormat: @"Content is not a vCard"];
+ [self errorWithFormat: @"Content is empty."];
return fields;
}
sqlType = "VARCHAR2(256)";
allowsNull = YES;
},
+ {
+ columnName = c_component;
+ sqlType = "VARCHAR2(10)";
+ allowsNull = NO;
+ },
);
}
sqlType = "VARCHAR(256)";
allowsNull = YES;
},
+ {
+ columnName = c_component;
+ sqlType = "VARCHAR(10)";
+ allowsNull = NO;
+ },
);
}
+2008-03-03 Wolfgang Sourdeau <wsourdeau@inverse.ca>
+
+ * NGVCardReference.[hm]: new class module that implements the base
+ data type contained in a VLIST element.
+
+ * NGVList.[hm]: new class module that implements Thunderbird-style
+ personal mailing lists. Base mime-type is "text/x-vlist".
+
2008-02-08 Wolfgang Sourdeau <wsourdeau@inverse.ca>
* iCalRecurrenceRule.m ([iCalRecurrenceRule -wkst]): if no wkst
NSCalendarDate+ICal.h \
\
NGVCard.h \
+ NGVList.h \
+ NGVCardReference.h \
# NGVCardAddress.h \
# NGVCardStrArrayValue.h \
# NGVCardName.h \
iCalYearlyRecurrenceCalculator.m\
\
NGVCard.m \
+ NGVList.m \
+ NGVCardReference.m \
NGCardsSaxHandler.m \
# IcalElements.m
# IcalResponse.m
-
# framework support
NGCards_PCH_FILE = $(libNGCards_PCH_FILE)
@class NSDictionary;
@class NSString;
+/* this should be merged in a common definition headers with iCalAccessClass */
+typedef enum
+{
+ NGCardsAccessPublic = 0,
+ NGCardsAccessPrivate = 1,
+ NGCardsAccessConfidential = 2,
+} NGCardsAccessClass;
+
@interface NGVCard : CardGroup
+ (id) cardWithUid: (NSString *) _uid;
--- /dev/null
+/* NGVList.h - this file is part of NGCards
+ *
+ * Copyright (C) 2008 Inverse groupe conseil
+ *
+ * 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 2, 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.
+ */
+
+#ifndef NGVLIST_H
+#define NGVLIST_H
+
+#import "CardGroup.h"
+
+#import "NGVCard.h"
+
+@class NSArray;
+@class NSDictionary;
+@class NSString;
+
+@class NGVCardReference;
+
+@interface NGVList : CardGroup
+
++ (id) listWithUid: (NSString *) newUid;
+- (id) initWithUid: (NSString *) newUid;
+
+/* accessors */
+
+- (void) setProdID: (NSString *) newProdID;
+- (NSString *) prodID;
+- (void) setVersion: (NSString *) newVersion;
+- (NSString *) version;
+
+- (void) setUid: (NSString *) newUid;
+- (NSString *) uid;
+
+- (void) setAccessClass: (NSString *) newAccessClass;
+- (NSString *) accessClass;
+- (NGCardsAccessClass) symbolicAccessClass;
+- (BOOL) isPublic;
+
+- (void) setFn: (NSString *) newFn;
+- (NSString *) fn;
+- (void) setNickname: (NSString *) newNickname;
+- (NSString *) nickname;
+- (void) setDescription: (NSString *) newDescription;
+- (NSString *) description;
+
+- (void) addCardReference: (NGVCardReference *) newCardRef;
+- (void) deleteCardReference: (NGVCardReference *) cardRef;
+- (NSArray *) cardReferences;
+
+@end
+
+#endif /* NGVLIST_H */
--- /dev/null
+/* NGVList.m - this file is part of NGCards
+ *
+ * Copyright (C) 2008 Inverse groupe conseil
+ *
+ * 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 2, 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.
+ */
+
+#import <Foundation/NSArray.h>
+#import <Foundation/NSEnumerator.h>
+#import <Foundation/NSString.h>
+
+#import "NGVCardReference.h"
+
+#import "NGVList.h"
+
+@implementation NGVList
+
++ (id) listWithUid: (NSString *) _uid
+{
+ NGVList *newList;
+
+ newList = [[self alloc] initWithUid: _uid];
+ [newList autorelease];
+
+ return newList;
+}
+
+- (id) initWithUid: (NSString *) _uid
+{
+ if ((self = [self init]))
+ {
+ [self setTag: @"vlist"];
+ [self setUid: _uid];
+ [self setVersion: @"1.0"];
+ }
+
+ return self;
+}
+
+/* class mapping */
+- (Class) classForTag: (NSString *) classTag
+{
+ Class tagClass;
+
+ tagClass = Nil;
+ if ([classTag isEqualToString: @"PRODID"]
+ || [classTag isEqualToString: @"VERSION"]
+ || [classTag isEqualToString: @"UID"]
+ || [classTag isEqualToString: @"CLASS"]
+ || [classTag isEqualToString: @"FN"]
+ || [classTag isEqualToString: @"NICKNAME"]
+ || [classTag isEqualToString: @"DESCRIPTION"])
+ tagClass = [CardElement class];
+ else if ([classTag isEqualToString: @"CARD"])
+ tagClass = [NGVCardReference class];
+ else
+ tagClass = [super classForTag: classTag];
+
+ return tagClass;
+}
+
+- (void) setProdID: (NSString *) newProdID
+{
+ [[self uniqueChildWithTag: @"prodid"] setValue: 0 to: newProdID];
+}
+
+- (NSString *) prodID
+{
+ return [[self uniqueChildWithTag: @"prodid"] value: 0];
+}
+
+- (void) setVersion: (NSString *) newVersion
+{
+ [[self uniqueChildWithTag: @"version"] setValue: 0
+ to: newVersion];
+}
+
+- (NSString *) version
+{
+ return [[self uniqueChildWithTag: @"version"] value: 0];
+}
+
+- (void) setUid: (NSString *) newUid
+{
+ [[self uniqueChildWithTag: @"uid"] setValue: 0
+ to: newUid];
+}
+
+- (NSString *) uid
+{
+ return [[self uniqueChildWithTag: @"uid"] value: 0];
+}
+
+- (void) setAccessClass: (NSString *) newAccessClass
+{
+ [[self uniqueChildWithTag: @"class"] setValue: 0
+ to: newAccessClass];
+}
+
+- (NSString *) accessClass
+{
+ return [[self uniqueChildWithTag: @"class"] value: 0];
+}
+
+- (NGCardsAccessClass) symbolicAccessClass
+{
+ NGCardsAccessClass symbolicAccessClass;
+ NSString *accessClass;
+
+ accessClass = [[self accessClass] uppercaseString];
+ if ([accessClass isEqualToString: @"PRIVATE"])
+ symbolicAccessClass = NGCardsAccessPrivate;
+ else if ([accessClass isEqualToString: @"CONFIDENTIAL"])
+ symbolicAccessClass = NGCardsAccessConfidential;
+ else
+ symbolicAccessClass = NGCardsAccessPublic;
+
+ return symbolicAccessClass;
+}
+
+- (BOOL) isPublic
+{
+ return ([self symbolicAccessClass] == NGCardsAccessPublic);
+}
+
+- (void) setFn: (NSString *) newFn
+{
+ [[self uniqueChildWithTag: @"fn"] setValue: 0 to: newFn];
+}
+
+- (NSString *) fn
+{
+ return [[self uniqueChildWithTag: @"fn"] value: 0];
+}
+
+- (void) setNickname: (NSString *) newNickname
+{
+ [[self uniqueChildWithTag: @"nickname"] setValue: 0
+ to: newNickname];
+}
+
+- (NSString *) nickname
+{
+ return [[self uniqueChildWithTag: @"nickname"] value: 0];
+}
+
+- (void) setDescription: (NSString *) newDescription
+{
+ [[self uniqueChildWithTag: @"description"] setValue: 0
+ to: newDescription];
+}
+
+- (NSString *) description
+{
+ return [[self uniqueChildWithTag: @"description"] value: 0];
+}
+
+- (void) addCardReference: (NGVCardReference *) newCardRef
+{
+ [self addChild: newCardRef];
+}
+
+- (void) deleteCardReference: (NGVCardReference *) cardRef
+{
+ NSEnumerator *cardReferences;
+ NGVCardReference *currentRef;
+ NSMutableArray *deletedRefs;
+
+ deletedRefs = [NSMutableArray array];
+ cardReferences
+ = [[self childrenWithTag: @"card"] objectEnumerator];
+ while ((currentRef = [cardReferences nextObject]))
+ if ([[currentRef reference]
+ isEqualToString: [cardRef reference]])
+ [deletedRefs addObject: currentRef];
+
+ [children removeObjectsInArray: deletedRefs];
+}
+
+- (NSArray *) cardReferences
+{
+ return [self childrenWithTag: @"card"];
+}
+
+@end
{
name = "VSCardSaxDriver";
sourceTypes = ( "text/x-vcard", "text/vcard",
+ "text/x-vlist",
"text/x-calendar", "text/calendar" );
}
);
--- /dev/null
+#!/bin/bash
+
+# this script only work with PostgreSQL
+
+defaultusername=$USER
+defaulthostname=localhost
+defaultdatabase=$USER
+indextable=sogo_folder_info
+
+read -p "Username ($defaultusername): " username
+read -p "Hostname ($defaulthostname): " hostname
+read -p "Database ($defaultdatabase): " database
+
+if [ -z "$username" ]
+then
+ username=$defaultusername
+fi
+if [ -z "$hostname" ]
+then
+ hostname=$defaulthostname
+fi
+if [ -z "$database" ]
+then
+ database=$defaultdatabase
+fi
+
+echo ""
+echo "You will now be requested your password twice..."
+echo "After that, a list of SQL operations will scroll."
+echo ""
+
+sqlscript=""
+
+function addField() {
+ oldIFS="$IFS"
+ IFS=" "
+ part="`echo -e \"ALTER TABLE $table ADD COLUMN c_component VARCHAR(10) NOT NULL DEFAULT 'vcard';\\n\"`";
+ sqlscript="$sqlscript$part"
+ IFS="$oldIFS"
+}
+
+tables=`psql -t -U $username -h $hostname $database -c "select split_part(c_quick_location, '/', 5) from $indextable where c_folder_type = 'Contact';"`
+
+for table in $tables;
+do
+ addField
+done
+
+echo "$sqlscript" | psql -q -e -U $username -h $hostname $database > /dev/null
+
+echo "Please ignore the errors above. They just mean that the migration was already done for the elements in question.";
/* name lookup */
-- (BOOL) isValidAppointmentName: (NSString *)_key
-{
- return ([_key length] != 0);
-}
-
- (void) appendObject: (NSDictionary *) object
withBaseURL: (NSString *) baseURL
toREPORTResponse: (WOResponse *) r
obj = [super lookupName:_key inContext:_ctx acquire:NO];
if (!obj)
{
- if ([self isValidAppointmentName:_key])
+ if ([self isValidContentName:_key])
{
url = [[[_ctx request] uri] urlWithoutParameters];
if ([url hasSuffix: @"AsTask"])
return r;
}
+- (BOOL) isFolderish
+{
+ return NO;
+}
+
- (NSString *) davContentType
{
return @"text/calendar";
};
classes = {
- SOGoAppointmentFolder = {
+ SOGoAppointmentFolders = {
superclass = "SOGoParentFolder";
};
SOGoAppointmentFolder = {
SOGoFolder+CardDAV.m \
SOGoContactFolders.m \
SOGoContactGCSEntry.m \
+ SOGoContactGCSList.m \
SOGoContactGCSFolder.m \
SOGoContactLDIFEntry.m \
SOGoContactLDAPFolder.m \
@class NGVCard;
-@interface SOGoContactGCSEntry : SOGoContentObject <SOGoContactObject>
+@interface SOGoContactGCSEntry
+ : SOGoContentObject <SOGoContactObject>
{
NGVCard *card;
}
#import <NGObjWeb/WOResponse.h>
#import <NGExtensions/NSObject+Logs.h>
#import <NGExtensions/NSString+misc.h>
+#import <NGCards/CardGroup.h>
#import <EOControl/EOQualifier.h>
#import <EOControl/EOSortOrdering.h>
#import <GDLContentStore/GCSFolder.h>
-#import <SoObjects/SOGo/NSDictionary+Utilities.h>
+#import <SOGo/SOGoCache.h>
+#import <SOGo/NSArray+Utilities.h>
+#import <SOGo/NSDictionary+Utilities.h>
+#import <SOGo/NSString+Utilities.h>
+
#import "SOGoContactGCSEntry.h"
+#import "SOGoContactGCSList.h"
+
#import "SOGoContactGCSFolder.h"
#define folderListingFields [NSArray arrayWithObjects: @"c_name", @"c_cn", \
return contact;
}
-- (id) lookupName: (NSString *) _key
- inContext: (WOContext *) _ctx
- acquire: (BOOL) _flag
+- (Class) objectClassForContent: (NSString *) content
{
- id obj;
- BOOL isPut;
+ CardGroup *cardEntry;
+ NSString *firstTag;
+ Class objectClass;
- isPut = NO;
- obj = [super lookupName:_key inContext:_ctx acquire:NO];
-
- if (!obj)
+ objectClass = Nil;
+
+ cardEntry = [CardGroup parseSingleFromSource: content];
+ if (cardEntry)
+ {
+ firstTag = [[cardEntry tag] uppercaseString];
+ if ([firstTag isEqualToString: @"VCARD"])
+ objectClass = [SOGoContactGCSEntry class];
+ else if ([firstTag isEqualToString: @"VLIST"])
+ objectClass = [SOGoContactGCSList class];
+ }
+
+ return objectClass;
+}
+
+- (Class) objectClassForResourceNamed: (NSString *) name
+{
+ EOQualifier *qualifier;
+ NSArray *records;
+ NSString *component;
+ Class objectClass;
+
+ qualifier = [EOQualifier qualifierWithQualifierFormat:@"c_name = %@", name];
+ records = [[self ocsFolder] fetchFields: [NSArray arrayWithObject: @"c_component"]
+ matchingQualifier: qualifier];
+
+ if ([records count])
{
- if ([[[_ctx request] method] isEqualToString: @"PUT"])
- {
- if ([_key isEqualToString: @"PUT"])
- isPut = YES;
- else
- obj = [SOGoContactGCSEntry objectWithName: _key
- inContainer: self];
- }
+ component = [[records objectAtIndex: 0] valueForKey: @"c_component"];
+ if ([component isEqualToString: @"vcard"])
+ objectClass = [SOGoContactGCSEntry class];
+ else if ([component isEqualToString: @"vlist"])
+ objectClass = [SOGoContactGCSList class];
else
- obj = [self lookupContactWithId: _key];
+ objectClass = Nil;
}
+ else
+ objectClass = Nil;
+
+ return objectClass;
+}
+
+- (id) deduceObjectForName: (NSString *)_key
+ inContext: (id)_ctx
+{
+ WORequest *request;
+ NSString *method;
+ Class objectClass;
+ id obj;
+
+ request = [_ctx request];
+ method = [request method];
+ if ([method isEqualToString: @"PUT"])
+ objectClass = [self objectClassForContent: [request contentAsString]];
+ else
+ objectClass = [self objectClassForResourceNamed: _key];
+
+ if (objectClass)
+ obj = [objectClass objectWithName: _key inContainer: self];
+ else
+ obj = nil;
+
+ return obj;
+}
+
+- (BOOL) requestNamedIsHandledLater: (NSString *) name
+{
+ return [name isEqualToString: @"OPTIONS"];
+}
+
+- (id) lookupName: (NSString *)_key
+ inContext: (id)_ctx
+ acquire: (BOOL)_flag
+{
+ id obj;
+ NSString *url;
+ BOOL handledLater;
+
+ /* first check attributes directly bound to the application */
+ handledLater = [self requestNamedIsHandledLater: _key];
+ if (handledLater)
+ obj = nil;
+ else
+ {
+ obj = [super lookupName:_key inContext:_ctx acquire:NO];
+ if (!obj)
+ {
+ if ([self isValidContentName: _key])
+ {
+ url = [[[_ctx request] uri] urlWithoutParameters];
+ if ([url hasSuffix: @"AsContact"])
+ obj = [SOGoContactGCSEntry objectWithName: _key
+ inContainer: self];
+ else if ([url hasSuffix: @"AsList"])
+ obj = [SOGoContactGCSList objectWithName: _key
+ inContainer: self];
+ else
+ obj = [self deduceObjectForName: _key
+ inContext: _ctx];
+ }
+ }
+ if (!obj)
+ obj = [NSException exceptionWithHTTPStatus:404 /* Not Found */];
+ }
+
+ if (obj)
+ [[SOGoCache sharedCache] registerObject: obj
+ withName: _key
+ inContainer: container];
+
+ return obj;
+}
+
+// - (id) lookupName: (NSString *) _key
+// inContext: (WOContext *) _ctx
+// acquire: (BOOL) _flag
+// {
+// id obj;
+// BOOL isPut;
+
+// isPut = NO;
+// obj = [super lookupName:_key inContext:_ctx acquire:NO];
+
+// if (!obj)
+// {
+// if ([[[_ctx request] method] isEqualToString: @"PUT"])
+// {
+// if ([_key isEqualToString: @"PUT"])
+// isPut = YES;
+// else
+
+// obj = [SOGoContactGCSEntry objectWithName: _key
+// inContainer: self];
+// }
+// else
+// obj = [self lookupContactWithId: _key];
+// }
// if (!(obj || isPut))
// obj = [NSException exceptionWithHTTPStatus:404 /* Not Found */];
// return [self contactWithName:_key inContext:_ctx];
// }
- /* return 404 to stop acquisition */
- return obj;
-}
+// /* return 404 to stop acquisition */
+// return obj;
+// }
/* fetching */
- (EOQualifier *) _qualifierForFilter: (NSString *) filter
cardDavCollection
= [NSArray arrayWithObjects: @"addressbook",
@"urn:ietf:params:xml:ns:carddav", nil];
-
resourceType = [NSMutableArray arrayWithArray: [super davResourceType]];
[resourceType addObject: cardDavCollection];
--- /dev/null
+/* SOGoContactGCSList.h - this file is part of SOGo
+ *
+ * Copyright (C) 2008 Inverse groupe conseil
+ *
+ * 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 2, 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.
+ */
+
+#ifndef SOGOCONTACTGCSLIST_H
+#define SOGOCONTACTGCSLIST_H
+
+#import <SOGo/SOGoContentObject.h>
+
+@class NGVList;
+
+@interface SOGoContactGCSList : SOGoContentObject
+{
+ NGVList *list;
+}
+
+@end
+
+#endif /* SOGOCONTACTGCSLIST_H */
--- /dev/null
+/* SOGoContactGCSList.m - this file is part of SOGo
+ *
+ * Copyright (C) 2008 Inverse groupe conseil
+ *
+ * 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 2, 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.
+ */
+
+#import <Foundation/NSDictionary.h>
+#import <Foundation/NSString.h>
+
+#import <NGCards/NGVList.h>
+
+#import "SOGoContactGCSList.h"
+
+@implementation SOGoContactGCSList
+
+- (id) init
+{
+ if ((self = [super init]))
+ {
+ list = nil;
+ }
+
+ return self;
+}
+
+- (void) dealloc
+{
+ [list release];
+ [super dealloc];
+}
+
+/* content */
+
+- (NGVList *) vList
+{
+ NSString *content;
+
+ if (!list)
+ {
+ content = [record objectForKey: @"c_content"];
+ if ([[content uppercaseString] hasPrefix: @"BEGIN:VLIST"])
+ list = [NGVList parseSingleFromSource: content];
+ else
+ list = [NGVList listWithUid: [self nameInContainer]];
+ [list retain];
+ }
+
+ return list;
+}
+
+/* DAV */
+
+- (NSString *) davContentType
+{
+ return @"text/x-vlist";
+}
+
+/* specialized actions */
+
+- (void) save
+{
+ NGVList *vlist;
+
+ vlist = [self vList];
+
+ [self saveContentString: [vlist versitString]];
+}
+
+/* message type */
+
+- (NSString *) outlookMessageClass
+{
+ return @"IPM.Contact";
+}
+
+@end
SOGoContactGCSEntry = {
superclass = "SOGoContentObject";
};
+ SOGoContactGCSList = {
+ superclass = "SOGoContentObject";
+ };
SOGoContactLDAPFolder = {
superclass = "SOGoGCSFolder";
protectedBy = "Access Contents Information";
NGImap4Connection *imap4;
}
+- (BOOL) isFolderish;
+
- (id) initWithImap4URL: (NSURL *) _url
inContainer: (id) _container;
[super dealloc];
}
+- (BOOL) isFolderish
+{
+ return YES;
+}
+
/* hierarchy */
- (SOGoMailAccount *) mailAccountFolder
return klazz;
}
+- (BOOL) isFolderish
+{
+ return NO;
+}
+
/* etag support */
- (id)davEntityTag {
reason:@"this object cannot be copied via WebDAV"];
}
-- (BOOL)davIsCollection {
- return [self isFolderish];
-}
-
/* acls */
- (NSArray *) aclUsers
- (NSString *) folderType;
- (NSArray *) fetchContentObjectNames;
+- (BOOL) isValidContentName: (NSString *) name;
+
/* sorting */
- (NSComparisonResult) compare: (id) otherFolder;
return [NSArray array];
}
+- (BOOL) isValidContentName: (NSString *) name
+{
+ return ([name length] > 0);
+}
+
- (BOOL) isFolderish
{
return YES;
/* WebDAV */
-- (BOOL) davIsCollection
-{
- return [self isFolderish];
-}
-
- (NSString *) davContentType
{
return @"httpd/unix-directory";
return [NSNumber numberWithBool:YES]; /* delete worked out ... */
}
+- (BOOL) isFolderish
+{
+ [self subclassResponsibility: _cmd];
+
+ return NO;
+}
+
+- (BOOL) davIsCollection
+{
+ return [self isFolderish];
+}
+
- (NSString *) davContentType
{
return @"text/plain";
UIxContactsFilterPanel.m \
UIxContactView.m \
UIxContactEditor.m \
+ UIxListView.m \
+ UIxListEditor.m \
UIxContactsListView.m \
UIxContactsListViewContainer.m \
UIxContactFoldersView.m \
#import <NGObjWeb/NSException+HTTP.h>
#import <NGObjWeb/SoObject.h>
#import <NGObjWeb/WORequest.h>
+#import <NGObjWeb/WOResponse.h>
#import <NGExtensions/NSNull+misc.h>
#import <NGCards/NGVCard.h>
#import <NGCards/NSArray+NGCards.h>
#import <Contacts/SOGoContactObject.h>
-#import <Contacts/SOGoContactFolder.h>
+#import <Contacts/SOGoContactGCSEntry.h>
+#import <Contacts/SOGoContactGCSFolder.h>
#import "UIxContactEditor.h"
/* accessors */
+- (NSString *) saveURL
+{
+ return [NSString stringWithFormat: @"%@/saveAsContact",
+ [[self clientObject] baseURL]];
+}
+
- (NSArray *) htmlMailFormatList
{
static NSArray *htmlMailFormatItems = nil;
/* actions */
-- (BOOL) shouldTakeValuesFromRequest: (WORequest *) _rq
- inContext: (WOContext*) _c
+- (BOOL) shouldTakeValuesFromRequest: (WORequest *) request
+ inContext: (WOContext*) context
{
- return YES;
+ NSString *actionName;
+
+ actionName = [[request requestHandlerPath] lastPathComponent];
+
+ return ([[self clientObject] isKindOfClass: [SOGoContactGCSEntry class]]
+ && [actionName hasPrefix: @"save"]);
}
- (void) _setSnapshotValue: (NSString *) key
- (NSString *) editActionName
{
/* this is overridden in the mail based contacts UI to redirect to tb.edit */
- return @"edit";
+ return @"editAsContact";
}
- (CardElement *) _elementWithTag: (NSString *) tag
- (id <WOActionResults>) saveAction
{
- id <SOGoContactObject> contact;
+ SOGoContactGCSEntry *contact;
id result;
NSString *jsRefreshMethod;
return [self redirectToLocation: url];
}
+#warning Could this be part of a common parent with UIxAppointment/UIxTaskEditor/UIxListEditor ?
- (id) newAction
{
- // TODO: this is almost a DUP of UIxAppointmentEditor
- /*
- This method creates a unique ID and redirects to the "edit" method on the
- new ID.
- It is actually a folder method and should be defined on the folder.
-
- Note: 'clientObject' is the SOGoAppointmentFolder!
- Update: remember that there are group folders as well.
- */
- NSString *uri, *objectId, *nextMethod;
- SOGoObject <SOGoContactFolder> *co;
+ NSString *objectId, *method, *uri;
+ id <WOActionResults> result;
+ SOGoContactGCSFolder *co;
co = [self clientObject];
- if ([co respondsToSelector: @selector (globallyUniqueObjectId)])
- objectId = [co globallyUniqueObjectId];
+ objectId = [co globallyUniqueObjectId];
+ if ([objectId length] > 0)
+ {
+ method = [NSString stringWithFormat:@"%@/%@.vcf/editAsContact",
+ [co soURL], objectId];
+ uri = [self completeHrefForMethod: method];
+ result = [self redirectToLocation: uri];
+ }
else
- objectId = nil;
-
- if ([objectId length] == 0)
- return [NSException exceptionWithHTTPStatus: 500 /* Internal Error */
- reason: @"could not create a unique ID"];
+ result = [NSException exceptionWithHTTPStatus: 500 /* Internal Error */
+ reason: @"could not create a unique ID"];
- nextMethod = [NSString stringWithFormat: @"../%@.vcf/%@",
- objectId, [self editActionName]];
- uri = [self _completeURIForMethod: nextMethod];
-
- return [self redirectToLocation: uri];
+ return result;
}
@end /* UIxContactEditor */
--- /dev/null
+/* UIxListEditor.h - this file is part of SOGo
+ *
+ * Copyright (C) 2008 Inverse groupe conseil
+ *
+ * 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 2, 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.
+ */
+
+#ifndef UIXLISTEDITOR_H
+#define UIXLISTEDITOR_H
+
+#import <SOGoUI/UIxComponent.h>
+
+@interface UIxListEditor : UIxComponent
+
+@end
+
+#endif /* UIXLISTEDITOR_H */
--- /dev/null
+/* UIxListEditor.m - this file is part of SOGo
+ *
+ * Copyright (C) 2008 Inverse groupe conseil
+ *
+ * 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 2, 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.
+ */
+
+#import <NGObjWeb/NSException+HTTP.h>
+#import <NGObjWeb/WOResponse.h>
+
+#import <Contacts/SOGoContactGCSFolder.h>
+
+#import "UIxListEditor.h"
+
+@implementation UIxListEditor
+
+- (NSString *) saveURL
+{
+ return [NSString stringWithFormat: @"%@/saveAsList",
+ [[self clientObject] baseURL]];
+}
+
+#warning Could this be part of a common parent with UIxAppointment/UIxTaskEditor/UIxListEditor ?
+- (id) newAction
+{
+ NSString *objectId, *method, *uri;
+ id <WOActionResults> result;
+ SOGoContactGCSFolder *co;
+
+ co = [self clientObject];
+ objectId = [co globallyUniqueObjectId];
+ if ([objectId length] > 0)
+ {
+ method = [NSString stringWithFormat:@"%@/%@.vls/editAsList",
+ [co soURL], objectId];
+ uri = [self completeHrefForMethod: method];
+ result = [self redirectToLocation: uri];
+ }
+ else
+ result = [NSException exceptionWithHTTPStatus: 500 /* Internal Error */
+ reason: @"could not create a unique ID"];
+
+ return result;
+}
+
+@end
--- /dev/null
+/* UIxListView.h - this file is part of SOGo
+ *
+ * Copyright (C) 2008 Inverse groupe conseil
+ *
+ * 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 2, 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.
+ */
+
+#ifndef UIXLISTVIEW_H
+#define UIXLISTVIEW_H
+
+#import <SOGoUI/UIxComponent.h>
+
+@interface UIxListView : UIxComponent
+
+@end
+
+#endif /* UIXLISTVIEW_H */
--- /dev/null
+/* UIxListView.m - this file is part of SOGo
+ *
+ * Copyright (C) 2008 Inverse groupe conseil
+ *
+ * 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 2, 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.
+ */
+
+#import "UIxListView.h"
+
+@implementation UIxListView
+
+@end
protectedBy = "View";
pageName = "UIxContactsListView";
};
- new = {
+ newcontact = {
protectedBy = "Add Documents, Images, and Files";
pageName = "UIxContactEditor";
actionName = "new";
};
+ newlist = {
+ protectedBy = "Add Documents, Images, and Files";
+ pageName = "UIxListEditor";
+ actionName = "new";
+ };
mailer-contacts = {
protectedBy = "View";
pageName = "UIxContactsListView";
protectedBy = "Access Contents Information";
pageName = "UIxContactEditor";
};
+ editAsContact = {
+ protectedBy = "Access Contents Information";
+ pageName = "UIxContactEditor";
+ };
save = {
protectedBy = "Change Images And Files";
pageName = "UIxContactEditor";
actionName = "save";
};
+ saveAsContact = {
+ protectedBy = "Change Images And Files";
+ pageName = "UIxContactEditor";
+ actionName = "save";
+ };
write = {
protectedBy = "View";
pageName = "UIxContactEditor";
};
};
+ SOGoContactGCSList = {
+ methods = {
+ view = {
+ protectedBy = "Access Contents Information";
+ pageName = "UIxListView";
+ };
+ delete = {
+ protectedBy = "Delete Objects";
+ pageName = "UIxListView";
+ actionName = "delete";
+ };
+ edit = {
+ protectedBy = "Access Contents Information";
+ pageName = "UIxListEditor";
+ };
+ editAsList = {
+ protectedBy = "Access Contents Information";
+ pageName = "UIxListEditor";
+ };
+ save = {
+ protectedBy = "Change Images And Files";
+ pageName = "UIxListEditor";
+ actionName = "save";
+ };
+ saveAsList = {
+ protectedBy = "Change Images And Files";
+ pageName = "UIxListEditor";
+ actionName = "save";
+ };
+ };
+ };
+
SOGoContactLDIFEntry = {
methods = {
view = {
};
};
}
-
- (NSString *) saveURL
{
return [NSString stringWithFormat: @"%@/saveAsAppointment",
- [[self clientObject] baseURL]];
+ [[self clientObject] baseURL]];
}
/* icalendar values */
title="name"
const:popup="YES"
>
- <form var:href="clientObject.baseURL" name="editform"
+ <form var:href="saveURL" name="editform"
onsubmit="return validateContactEditor()">
<div class="tabsContainer" id="editorTabs">
</div>
<div id="buttons">
<input
- type="submit"
+ id="cancelButton"
+ type="button"
class="button"
label:value="Cancel"
- name="cancel"
- onclick="window.close(); return false;" />
+ name="cancel"/>
<var:if condition="canCreateOrModify"
><input
type="submit"
class="button"
label:value="Save"
- name="save:method" /></var:if>
+ name="submit" /></var:if>
</div>
</form>
</var:component>
--- /dev/null
+<?xml version='1.0' standalone='yes'?>
+ <var:component
+ xmlns="http://www.w3.org/1999/xhtml"
+ xmlns:var="http://www.skyrix.com/od/binding"
+ xmlns:const="http://www.skyrix.com/od/constant"
+ xmlns:rsrc="OGo:url"
+ xmlns:label="OGo:label"
+ xmlns:uix="OGo:uix"
+ className="UIxPageFrame"
+ title="name"
+ const:popup="YES"
+ >Unimplemented</var:component>
--- /dev/null
+<?xml version='1.0' standalone='yes'?>
+ <var:component
+ xmlns="http://www.w3.org/1999/xhtml"
+ xmlns:var="http://www.skyrix.com/od/binding"
+ xmlns:const="http://www.skyrix.com/od/constant"
+ xmlns:rsrc="OGo:url"
+ xmlns:label="OGo:label"
+ xmlns:uix="OGo:uix"
+ className="UIxPageFrame"
+ title="name"
+ const:popup="YES"
+ >Unimplemented</var:component>
<input type="hidden" name="range2"
id="range2"
var:value="range2"/>
-
-
</div>
</form>
</var:component>
}
function newContact(sender) {
- openContactWindow(URLForFolderID(currentContactFolder) + "/new");
+ openContactWindow(URLForFolderID(currentContactFolder) + "/newcontact");
return false; /* stop following the link */
}
return true;
}
+function onEditorCancelClick(event) {
+ preventDefault(event);
+ window.close();
+}
+
function initEditorForm() {
displayNameChanged = ($("fn").value.length > 0);
$("fn").onkeydown = onFnKeyDown;
$("sn").onkeyup = onFnNewValue;
$("givenName").onkeyup = onFnNewValue;
+
+ $("cancelButton").observe("click", onEditorCancelClick);
}
FastInit.addOnLoad(initEditorForm);
var list = $("attachments");
$(list).attachMenu("attachmentsMenu");
var elements = list.childNodesWithTag("li");
- for (var i = 0; i < elements.length; i++) {
- Event.observe(elements[i], "click",
- onRowClick.bindAsEventListener(elements[i]));
- }
+ for (var i = 0; i < elements.length; i++)
+ elements[i].observe("click", onRowClick);
var listContent = $("attachments").childNodesWithTag("li");
if (listContent.length > 0)