diff --git a/ChangeLog b/ChangeLog index b5b95d531..9e7a22650 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,21 @@ +2010-11-03 Wolfgang Sourdeau + + * Tests/Integration/teststrings.sh: new utility script to test the + parsability of the localization strings file. + + * UI/WebServerResources/generic.js: (onCASRecoverIFrameLoaded): + go back to the user's page instead of the logoff page. + +2010-11-02 Ludovic Marcotte + + * Implemented http://sogo.nu/bugs/view.php?id=821 + +2010-11-02 Wolfgang Sourdeau + + * SoObjects/SOGo/NSDictionary+BSJSONAdditions.[hm]: + SoObjects/SOGo/NSScanner+BSJSONAdditions.[hm]: removed classes, + obsoleted by the use of the SBJson library. + 2010-11-01 Francis Lachapelle * UI/WebServerResources/MailerUI.js (mailListToggleMessagesRead): @@ -19,6 +37,30 @@ 2010-11-01 Wolfgang Sourdeau + * SoObjects/Appointments/SOGoAptMailUpdate.m (-setupValues): avoid + setting values that are already set in SOGoAptMailNotification. + + * SoObjects/Appointments/SOGoAptMailDeletion.m (-getBody): added + the same details as for the meeting invitations. + + * SoObjects/Appointments/SOGoAptMailNotification.m (-setupValues): + merged setup code from SOGoAptMailInvitation.m. + + * UI/WebServerResources/ContactsUI.js: (resetCategoriesMenu) + (onCategoriesMenuPrepareVisibility, onCategoriesMenuItemClick) + (setCategoryOnNode, unsetCategoryOnNode): new methods designed to + handle the handling of categories directly from the contacts list. + + * SoObjects/Contacts/SOGoContactGCSFolder.m (+initialize): we now + return the "c_categories" field too. + + * UI/Contacts/UIxContactActions.m: new class module implementing + actions on contacts. + (-setCategoryAction, -unsetCategoryAction): new actions. + + * UI/WebServerResources/generic.js (triggerAjaxRequest): invoke + the request callback only when set on the http object. + * SoObjects/Mailer/SOGoMailBaseObject.m (-_createIMAP4Connection): we need to initialize newConnection to nil when the return password is nil. diff --git a/Documentation/SOGo Installation Guide.odt b/Documentation/SOGo Installation Guide.odt index 41436dc79..f1abb478b 100644 Binary files a/Documentation/SOGo Installation Guide.odt and b/Documentation/SOGo Installation Guide.odt differ diff --git a/GNUmakefile b/GNUmakefile index af8be3570..ba362d698 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -6,8 +6,8 @@ include $(GNUSTEP_MAKEFILES)/common.make SUBPROJECTS = \ SOPE/NGCards \ SOPE/GDLContentStore \ - OGoContentStore \ SoObjects \ + OGoContentStore \ Main \ UI \ Tools diff --git a/OGoContentStore/GNUmakefile.preamble b/OGoContentStore/GNUmakefile.preamble index 0d0184bdd..01bd0b897 100644 --- a/OGoContentStore/GNUmakefile.preamble +++ b/OGoContentStore/GNUmakefile.preamble @@ -9,7 +9,7 @@ libOGoContentStore_LIBRARIES_DEPEND_UPON += \ -lSaxObjC \ -lSOGo -ADDITIONAL_INCLUDE_DIRS += -I. -I.. -I../SOPE +ADDITIONAL_INCLUDE_DIRS += -I. -I.. -I../SOPE -I../SoObjects ADDITIONAL_LIB_DIRS += -L./$(GNUSTEP_OBJ_DIR) -L../SOPE/NGCards/$(GNUSTEP_OBJ_DIR)/ -L../SoObjects/SOGo/SOGo.framework/ diff --git a/SoObjects/Appointments/BrazilianPortuguese.lproj/Localizable.strings b/SoObjects/Appointments/BrazilianPortuguese.lproj/Localizable.strings index e23635767..bbb7b04cb 100644 --- a/SoObjects/Appointments/BrazilianPortuguese.lproj/Localizable.strings +++ b/SoObjects/Appointments/BrazilianPortuguese.lproj/Localizable.strings @@ -39,8 +39,8 @@ vtodo_class2 = "(Tarefa Confidencial)"; /* Deletion */ "Event Cancelled: \"%{Summary}\"" = "Event Cancelled: \"%{Summary}\""; -"%{Organizer} %{SentByText}has cancelled this event: %{Summary}." -= "%{Organizer} %{SentByText}has cancelled this event: %{Summary}."; +"%{Organizer} %{SentByText}has cancelled this event: %{Summary}.\n\nStart: %{StartDate} at %{StartTime}\nEnd: %{EndDate} at %{EndTime}\nDescription: %{Description}" += "%{Organizer} %{SentByText}has cancelled this event: %{Summary}.\n\nStart: %{StartDate} at %{StartTime}\nEnd: %{EndDate} at %{EndTime}\nDescription: %{Description}"; /* Update */ "The appointment \"%{Summary}\" for the %{OldStartDate} at %{OldStartTime} has changed" diff --git a/SoObjects/Appointments/Catalan.lproj/Localizable.strings b/SoObjects/Appointments/Catalan.lproj/Localizable.strings index 79ef794cc..6cd264e20 100644 --- a/SoObjects/Appointments/Catalan.lproj/Localizable.strings +++ b/SoObjects/Appointments/Catalan.lproj/Localizable.strings @@ -39,8 +39,8 @@ vtodo_class2 = "(Tasca confidencial)"; /* Deletion */ "Event Cancelled: \"%{Summary}\"" = "Esdeveniment suspès: \"%{Summary}\""; -"%{Organizer} %{SentByText}has cancelled this event: %{Summary}." -= "%{Organizer} %{SentByText}ha suspès aquest esdeveniment: %{Summary}."; +"%{Organizer} %{SentByText}has cancelled this event: %{Summary}.\n\nStart: %{StartDate} at %{StartTime}\nEnd: %{EndDate} at %{EndTime}\nDescription: %{Description}" += "%{Organizer} %{SentByText}ha suspès aquest esdeveniment: %{Summary}.\n\nStart: %{StartDate} at %{StartTime}\nEnd: %{EndDate} at %{EndTime}\nDescription: %{Description}"; /* Update */ "The appointment \"%{Summary}\" for the %{OldStartDate} at %{OldStartTime} has changed" diff --git a/SoObjects/Appointments/Czech.lproj/Localizable.strings b/SoObjects/Appointments/Czech.lproj/Localizable.strings index 15c40336f..603333459 100644 --- a/SoObjects/Appointments/Czech.lproj/Localizable.strings +++ b/SoObjects/Appointments/Czech.lproj/Localizable.strings @@ -39,8 +39,8 @@ vtodo_class2 = "(Skrytý úkol)"; /* Deletion */ "Event Cancelled: \"%{Summary}\"" = "Zrušení události: \"%{Summary}\""; -"%{Organizer} %{SentByText}has cancelled this event: %{Summary}." -= "%{Organizer} %{SentByText}zrušil/a událost: %{Summary}."; +"%{Organizer} %{SentByText}has cancelled this event: %{Summary}.\n\nStart: %{StartDate} at %{StartTime}\nEnd: %{EndDate} at %{EndTime}\nDescription: %{Description}" += "%{Organizer} %{SentByText}zrušil/a událost: %{Summary}.\n\nStart: %{StartDate} at %{StartTime}\nEnd: %{EndDate} at %{EndTime}\nDescription: %{Description}"; /* Update */ "The appointment \"%{Summary}\" for the %{OldStartDate} at %{OldStartTime} has changed" diff --git a/SoObjects/Appointments/Dutch.lproj/Localizable.strings b/SoObjects/Appointments/Dutch.lproj/Localizable.strings index 4f9088aae..b68771cde 100644 --- a/SoObjects/Appointments/Dutch.lproj/Localizable.strings +++ b/SoObjects/Appointments/Dutch.lproj/Localizable.strings @@ -39,8 +39,8 @@ vtodo_class2 = "(Vertrouwelijke taak)"; /* Deletion */ "Event Cancelled: \"%{Summary}\"" = "Event Cancelled: \"%{Summary}\""; -"%{Organizer} %{SentByText}has cancelled this event: %{Summary}." -= "%{Organizer} %{SentByText}has cancelled this event: %{Summary}."; +"%{Organizer} %{SentByText}has cancelled this event: %{Summary}.\n\nStart: %{StartDate} at %{StartTime}\nEnd: %{EndDate} at %{EndTime}\nDescription: %{Description}" += "%{Organizer} %{SentByText}has cancelled this event: %{Summary}.\n\nStart: %{StartDate} at %{StartTime}\nEnd: %{EndDate} at %{EndTime}\nDescription: %{Description}"; /* Update */ "The appointment \"%{Summary}\" for the %{OldStartDate} at %{OldStartTime} has changed" diff --git a/SoObjects/Appointments/English.lproj/Localizable.strings b/SoObjects/Appointments/English.lproj/Localizable.strings index 2fc0234bb..01a973e0c 100644 --- a/SoObjects/Appointments/English.lproj/Localizable.strings +++ b/SoObjects/Appointments/English.lproj/Localizable.strings @@ -39,8 +39,8 @@ vtodo_class2 = "(Confidential task)"; /* Deletion */ "Event Cancelled: \"%{Summary}\"" = "Event Cancelled: \"%{Summary}\""; -"%{Organizer} %{SentByText}has cancelled this event: %{Summary}." -= "%{Organizer} %{SentByText}has cancelled this event: %{Summary}."; +"%{Organizer} %{SentByText}has cancelled this event: %{Summary}.\n\nStart: %{StartDate} at %{StartTime}\nEnd: %{EndDate} at %{EndTime}\nDescription: %{Description}" += "%{Organizer} %{SentByText}has cancelled this event: %{Summary}.\n\nStart: %{StartDate} at %{StartTime}\nEnd: %{EndDate} at %{EndTime}\nDescription: %{Description}"; /* Update */ "The appointment \"%{Summary}\" for the %{OldStartDate} at %{OldStartTime} has changed" diff --git a/SoObjects/Appointments/French.lproj/Localizable.strings b/SoObjects/Appointments/French.lproj/Localizable.strings index 64d040a1f..bf6ef31f2 100644 --- a/SoObjects/Appointments/French.lproj/Localizable.strings +++ b/SoObjects/Appointments/French.lproj/Localizable.strings @@ -39,8 +39,8 @@ vtodo_class2 = "(Tâche confidentielle)"; /* Deletion */ "Event Cancelled: \"%{Summary}\"" = "Réunion annulée : « %{Summary} »"; -"%{Organizer} %{SentByText}has cancelled this event: %{Summary}." -= "%{Organizer} %{SentByText}a annulé cette réunion : « %{Summary} »"; +"%{Organizer} %{SentByText}has cancelled this event: %{Summary}.\n\nStart: %{StartDate} at %{StartTime}\nEnd: %{EndDate} at %{EndTime}\nDescription: %{Description}" += "%{Organizer} %{SentByText}a annulé cette réunion : « %{Summary} ».\n\nDébut: %{StartDate} à %{StartTime}\nFin: %{EndDate} à %{EndTime}\nDescription: %{Description}"; /* Update */ "The appointment \"%{Summary}\" for the %{OldStartDate} at %{OldStartTime} has changed" diff --git a/SoObjects/Appointments/German.lproj/Localizable.strings b/SoObjects/Appointments/German.lproj/Localizable.strings index 5ad0feafa..b091b932b 100644 --- a/SoObjects/Appointments/German.lproj/Localizable.strings +++ b/SoObjects/Appointments/German.lproj/Localizable.strings @@ -39,8 +39,8 @@ vtodo_class2 = "(Vertrauliche Aufgabe)"; /* Deletion */ "Event Cancelled: \"%{Summary}\"" = "Termin abgesagt: \"%{Summary}\""; -"%{Organizer} %{SentByText}has cancelled this event: %{Summary}." -= "%{Organizer} %{SentByText}hat diesen Termin abgesagt: %{Summary}."; +"%{Organizer} %{SentByText}has cancelled this event: %{Summary}.\n\nStart: %{StartDate} at %{StartTime}\nEnd: %{EndDate} at %{EndTime}\nDescription: %{Description}" += "%{Organizer} %{SentByText}hat diesen Termin abgesagt: %{Summary}.\n\nStart: %{StartDate} at %{StartTime}\nEnd: %{EndDate} at %{EndTime}\nDescription: %{Description}"; /* Update */ "The appointment \"%{Summary}\" for the %{OldStartDate} at %{OldStartTime} has changed" diff --git a/SoObjects/Appointments/Hungarian.lproj/Localizable.strings b/SoObjects/Appointments/Hungarian.lproj/Localizable.strings index e3d79698a..a3640e7a7 100644 --- a/SoObjects/Appointments/Hungarian.lproj/Localizable.strings +++ b/SoObjects/Appointments/Hungarian.lproj/Localizable.strings @@ -39,8 +39,8 @@ vtodo_class2 = "(Bizalmas feladat)"; /* Deletion */ "Event Cancelled: \"%{Summary}\"" = "Event Cancelled: \"%{Summary}\""; -"%{Organizer} %{SentByText}has cancelled this event: %{Summary}." -= "%{Organizer} %{SentByText}has cancelled this event: %{Summary}."; +"%{Organizer} %{SentByText}has cancelled this event: %{Summary}.\n\nStart: %{StartDate} at %{StartTime}\nEnd: %{EndDate} at %{EndTime}\nDescription: %{Description}" += "%{Organizer} %{SentByText}has cancelled this event: %{Summary}.\n\nStart: %{StartDate} at %{StartTime}\nEnd: %{EndDate} at %{EndTime}\nDescription: %{Description}"; /* Update */ "The appointment \"%{Summary}\" for the %{OldStartDate} at %{OldStartTime} has changed" diff --git a/SoObjects/Appointments/Italian.lproj/Localizable.strings b/SoObjects/Appointments/Italian.lproj/Localizable.strings index 4567bce4a..cfa1123f4 100644 --- a/SoObjects/Appointments/Italian.lproj/Localizable.strings +++ b/SoObjects/Appointments/Italian.lproj/Localizable.strings @@ -39,8 +39,8 @@ vtodo_class2 = "(Attività confidenziale)"; /* Deletion */ "Event Cancelled: \"%{Summary}\"" = "Evento cancellato: \"%{Summary}\""; -"%{Organizer} %{SentByText}has cancelled this event: %{Summary}." -= "%{Organizer} %{SentByText}ha cancellato questo evento: %{Summary}."; +"%{Organizer} %{SentByText}has cancelled this event: %{Summary}.\n\nStart: %{StartDate} at %{StartTime}\nEnd: %{EndDate} at %{EndTime}\nDescription: %{Description}" += "%{Organizer} %{SentByText}ha cancellato questo evento: %{Summary}.\n\nStart: %{StartDate} at %{StartTime}\nEnd: %{EndDate} at %{EndTime}\nDescription: %{Description}"; /* Update */ "The appointment \"%{Summary}\" for the %{OldStartDate} at %{OldStartTime} has changed" diff --git a/SoObjects/Appointments/Polish.lproj/Localizable.strings b/SoObjects/Appointments/Polish.lproj/Localizable.strings index 59474334f..66c83afb4 100644 --- a/SoObjects/Appointments/Polish.lproj/Localizable.strings +++ b/SoObjects/Appointments/Polish.lproj/Localizable.strings @@ -39,8 +39,8 @@ vtodo_class2 = "(Zadanie poufne)"; /* Deletion */ "Event Cancelled: \"%{Summary}\"" = "Wydarzenie anulowane: \"%{Summary}\""; -"%{Organizer} %{SentByText}has cancelled this event: %{Summary}." -= "%{Organizer} %{SentByText}anulował(a) to wydarzenie: %{Summary}."; +"%{Organizer} %{SentByText}has cancelled this event: %{Summary}.\n\nStart: %{StartDate} at %{StartTime}\nEnd: %{EndDate} at %{EndTime}\nDescription: %{Description}" += "%{Organizer} %{SentByText}anulował(a) to wydarzenie: %{Summary}.\n\nStart: %{StartDate} at %{StartTime}\nEnd: %{EndDate} at %{EndTime}\nDescription: %{Description}"; /* Update */ "The appointment \"%{Summary}\" for the %{OldStartDate} at %{OldStartTime} has changed" diff --git a/SoObjects/Appointments/Russian.lproj/Localizable.strings b/SoObjects/Appointments/Russian.lproj/Localizable.strings index 8d7066aeb..d33d98bca 100644 --- a/SoObjects/Appointments/Russian.lproj/Localizable.strings +++ b/SoObjects/Appointments/Russian.lproj/Localizable.strings @@ -39,8 +39,8 @@ vtodo_class2 = "(Confidential task)"; /* Deletion */ "Event Cancelled: \"%{Summary}\"" = "Event Cancelled: \"%{Summary}\""; -"%{Organizer} %{SentByText}has cancelled this event: %{Summary}." -= "%{Organizer} %{SentByText}has cancelled this event: %{Summary}."; +"%{Organizer} %{SentByText}has cancelled this event: %{Summary}.\n\nStart: %{StartDate} at %{StartTime}\nEnd: %{EndDate} at %{EndTime}\nDescription: %{Description}" += "%{Organizer} %{SentByText}has cancelled this event: %{Summary}.\n\nStart: %{StartDate} at %{StartTime}\nEnd: %{EndDate} at %{EndTime}\nDescription: %{Description}"; /* Update */ "The appointment \"%{Summary}\" for the %{OldStartDate} at %{OldStartTime} has changed" diff --git a/SoObjects/Appointments/SOGoAptMailDeletion.m b/SoObjects/Appointments/SOGoAptMailDeletion.m index 2163e763c..5db61e955 100644 --- a/SoObjects/Appointments/SOGoAptMailDeletion.m +++ b/SoObjects/Appointments/SOGoAptMailDeletion.m @@ -49,8 +49,11 @@ if (!values) [self setupValues]; - bodyFormat = [self labelForKey: @"%{Organizer} %{SentByText}has" - @" cancelled this event: %{Summary}." + bodyFormat = [self labelForKey: (@"%{Organizer} %{SentByText}has cancelled" + @" this event: %{Summary}.\n\n" + @"Start: %{StartDate} at %{StartTime}\n" + @"End: %{EndDate} at %{EndTime}\n" + @"Description: %{Description}") inContext: context]; return [values keysWithFormat: bodyFormat]; diff --git a/SoObjects/Appointments/SOGoAptMailInvitation.m b/SoObjects/Appointments/SOGoAptMailInvitation.m index 389bbb0ce..d33d332f4 100644 --- a/SoObjects/Appointments/SOGoAptMailInvitation.m +++ b/SoObjects/Appointments/SOGoAptMailInvitation.m @@ -24,7 +24,6 @@ #import #import #import -#import #import #import "iCalPerson+SOGo.h" @@ -35,34 +34,6 @@ @implementation SOGoAptMailInvitation -- (void) setupValues -{ - SOGoDateFormatter *dateFormatter; - NSCalendarDate *date; - NSString *description; - - [super setupValues]; - - - dateFormatter = [[context activeUser] dateFormatterInContext: context]; - - date = [self newStartDate]; - [values setObject: [dateFormatter shortFormattedDate: date] - forKey: @"StartDate"]; - [values setObject: [dateFormatter formattedTime: date] - forKey: @"StartTime"]; - - date = [self newEndDate]; - [values setObject: [dateFormatter shortFormattedDate: date] - forKey: @"EndDate"]; - [values setObject: [dateFormatter formattedTime: date] - forKey: @"EndTime"]; - - description = [[self apt] comment]; - [values setObject: (description ? description : @"") - forKey: @"Description"]; -} - - (NSString *) getSubject { NSString *subjectFormat; diff --git a/SoObjects/Appointments/SOGoAptMailNotification.m b/SoObjects/Appointments/SOGoAptMailNotification.m index 5cc54cfac..85f2e6b39 100644 --- a/SoObjects/Appointments/SOGoAptMailNotification.m +++ b/SoObjects/Appointments/SOGoAptMailNotification.m @@ -34,6 +34,7 @@ #import #import #import +#import #import #import @@ -172,9 +173,11 @@ - (void) setupValues { + NSString *sentBy, *sentByText, *description; + NSCalendarDate *date; NSDictionary *sentByValues; - NSString *sentBy, *sentByText; SOGoUser *user; + SOGoDateFormatter *dateFormatter; user = [context activeUser]; viewTZ = [[user userDefaults] timeZone]; @@ -200,6 +203,25 @@ sentByText = @""; [values setObject: sentByText forKey: @"SentByText"]; } + + dateFormatter = [[context activeUser] dateFormatterInContext: context]; + + date = [self newStartDate]; + [values setObject: [dateFormatter shortFormattedDate: date] + forKey: @"StartDate"]; + [values setObject: [dateFormatter formattedTime: date] + forKey: @"StartTime"]; + + date = [self newEndDate]; + [values setObject: [dateFormatter shortFormattedDate: date] + forKey: @"EndDate"]; + [values setObject: [dateFormatter formattedTime: date] + forKey: @"EndTime"]; + + description = [[self apt] comment]; + [values setObject: (description ? description : @"") + forKey: @"Description"]; + } @end diff --git a/SoObjects/Appointments/SOGoAptMailUpdate.m b/SoObjects/Appointments/SOGoAptMailUpdate.m index a489f44f0..c6ef1f062 100644 --- a/SoObjects/Appointments/SOGoAptMailUpdate.m +++ b/SoObjects/Appointments/SOGoAptMailUpdate.m @@ -134,12 +134,6 @@ [values setObject: [dateFormatter formattedTime: date] forKey: @"OldStartTime"]; - date = [self newStartDate]; - [values setObject: [dateFormatter shortFormattedDate: date] - forKey: @"StartDate"]; - [values setObject: [dateFormatter formattedTime: date] - forKey: @"StartTime"]; - [self _setupBodyValuesWithFormatter: dateFormatter]; } diff --git a/SoObjects/Appointments/Spanish.lproj/Localizable.strings b/SoObjects/Appointments/Spanish.lproj/Localizable.strings index 46131df13..b1f66533b 100644 --- a/SoObjects/Appointments/Spanish.lproj/Localizable.strings +++ b/SoObjects/Appointments/Spanish.lproj/Localizable.strings @@ -39,8 +39,8 @@ vtodo_class2 = "(Tarea confidencial)"; /* Deletion */ "Event Cancelled: \"%{Summary}\"" = "Event Cancelled: \"%{Summary}\""; -"%{Organizer} %{SentByText}has cancelled this event: %{Summary}." -= "%{Organizer} %{SentByText}has cancelled this event: %{Summary}."; +"%{Organizer} %{SentByText}has cancelled this event: %{Summary}.\n\nStart: %{StartDate} at %{StartTime}\nEnd: %{EndDate} at %{EndTime}\nDescription: %{Description}" += "%{Organizer} %{SentByText}has cancelled this event: %{Summary}.\n\nStart: %{StartDate} at %{StartTime}\nEnd: %{EndDate} at %{EndTime}\nDescription: %{Description}"; /* Update */ "The appointment \"%{Summary}\" for the %{OldStartDate} at %{OldStartTime} has changed" diff --git a/SoObjects/Appointments/Swedish.lproj/Localizable.strings b/SoObjects/Appointments/Swedish.lproj/Localizable.strings index 14a93ef7a..c36b478ea 100644 --- a/SoObjects/Appointments/Swedish.lproj/Localizable.strings +++ b/SoObjects/Appointments/Swedish.lproj/Localizable.strings @@ -39,8 +39,8 @@ vtodo_class2 = "(Konfidentiell uppgift)"; /* Deletion */ "Event Cancelled: \"%{Summary}\"" = "Event Cancelled: \"%{Summary}\""; -"%{Organizer} %{SentByText}has cancelled this event: %{Summary}." -= "%{Organizer} %{SentByText}has cancelled this event: %{Summary}."; +"%{Organizer} %{SentByText}has cancelled this event: %{Summary}.\n\nStart: %{StartDate} at %{StartTime}\nEnd: %{EndDate} at %{EndTime}\nDescription: %{Description}" += "%{Organizer} %{SentByText}has cancelled this event: %{Summary}.\n\nStart: %{StartDate} at %{StartTime}\nEnd: %{EndDate} at %{EndTime}\nDescription: %{Description}"; /* Update */ "The appointment \"%{Summary}\" for the %{OldStartDate} at %{OldStartTime} has changed" diff --git a/SoObjects/Appointments/Ukrainian.lproj/Localizable.strings b/SoObjects/Appointments/Ukrainian.lproj/Localizable.strings index 0c7021993..eac4b5bf9 100644 --- a/SoObjects/Appointments/Ukrainian.lproj/Localizable.strings +++ b/SoObjects/Appointments/Ukrainian.lproj/Localizable.strings @@ -39,8 +39,8 @@ vtodo_class2 = "(Конфіденційне завдання)"; /* Deletion */ "Event Cancelled: \"%{Summary}\"" = "Подію скасовано: \"%{Summary}\""; -"%{Organizer} %{SentByText} скасував подію: %{Summary}." -= "%{Organizer} %{SentByText} скасував подію: %{Summary}."; +"%{Organizer} %{SentByText}has cancelled this event: %{Summary}.\n\nStart: %{StartDate} at %{StartTime}\nEnd: %{EndDate} at %{EndTime}\nDescription: %{Description}" += "%{Organizer} %{SentByText} скасував подію: %{Summary}.\n\nStart: %{StartDate} at %{StartTime}\nEnd: %{EndDate} at %{EndTime}\nDescription: %{Description}"; /* Update */ "The appointment \"%{Summary}\" for the %{OldStartDate} at %{OldStartTime} has changed" diff --git a/SoObjects/Appointments/Welsh.lproj/Localizable.strings b/SoObjects/Appointments/Welsh.lproj/Localizable.strings index 0522bb36d..bda59e824 100644 --- a/SoObjects/Appointments/Welsh.lproj/Localizable.strings +++ b/SoObjects/Appointments/Welsh.lproj/Localizable.strings @@ -39,8 +39,8 @@ vtodo_class2 = "(Tasg gyfrinachol)"; /* Deletion */ "Event Cancelled: \"%{Summary}\"" = "Event Cancelled: \"%{Summary}\""; -"%{Organizer} %{SentByText}has cancelled this event: %{Summary}." -= "%{Organizer} %{SentByText}has cancelled this event: %{Summary}."; +"%{Organizer} %{SentByText}has cancelled this event: %{Summary}.\n\nStart: %{StartDate} at %{StartTime}\nEnd: %{EndDate} at %{EndTime}\nDescription: %{Description}" += "%{Organizer} %{SentByText}has cancelled this event: %{Summary}.\n\nStart: %{StartDate} at %{StartTime}\nEnd: %{EndDate} at %{EndTime}\nDescription: %{Description}"; /* Update */ "The appointment \"%{Summary}\" for the %{OldStartDate} at %{OldStartTime} has changed" diff --git a/SoObjects/Contacts/SOGoContactGCSFolder.m b/SoObjects/Contacts/SOGoContactGCSFolder.m index b176e4da6..7279064e9 100644 --- a/SoObjects/Contacts/SOGoContactGCSFolder.m +++ b/SoObjects/Contacts/SOGoContactGCSFolder.m @@ -62,6 +62,7 @@ static NSArray *folderListingFields = nil; @"c_cn", @"c_givenname", @"c_sn", @"c_screenname", @"c_o", @"c_mail", @"c_telephonenumber", + @"c_categories", @"c_component", nil]; } diff --git a/SoObjects/Mailer/SOGoMailAccount.m b/SoObjects/Mailer/SOGoMailAccount.m index 42d432fed..e2d8e45ff 100644 --- a/SoObjects/Mailer/SOGoMailAccount.m +++ b/SoObjects/Mailer/SOGoMailAccount.m @@ -236,8 +236,9 @@ static NSString *sieveScriptName = @"sogo"; SOGoUserDefaults *ud; SOGoDomainDefaults *dd; NGSieveClient *client; - NSString *filterScript, *v, *password; + NSString *filterScript, *v, *password, *sieveServer; SOGoSieveConverter *converter; + int sievePort; BOOL b; dd = [[context activeUser] domainDefaults]; @@ -338,9 +339,36 @@ static NSString *sieveScriptName = @"sogo"; [script insertString: header atIndex: 0]; } - // We connect to our Sieve server and upload the script - address = [NGInternetSocketAddress addressWithPort: 2000 - onHost: [[self imap4URL] host]]; + // We connect to our Sieve server and upload the script. + // + // sieveServer might have the following format: + // + // sieve://localhost + // sieve://localhost:2000 + // + // Values such as "localhost" or "localhost:2000" are NOT supported. + // + sieveServer = [dd sieveServer]; + sievePort = 2000; + + if (!sieveServer) + { + sieveServer = @"localhost"; + } + else + { + NSURL *url; + + url = [NSURL URLWithString: sieveServer]; + + if ([url host]) + sieveServer = [url host]; + + if ([[url port] intValue] != 0) + sievePort = [[url port] intValue]; + } + + address = [NGInternetSocketAddress addressWithPort: sievePort onHost: sieveServer]; client = [NGSieveClient clientWithAddress: address]; diff --git a/SoObjects/SOGo/GNUmakefile b/SoObjects/SOGo/GNUmakefile index 88766c4e9..8733c5b15 100644 --- a/SoObjects/SOGo/GNUmakefile +++ b/SoObjects/SOGo/GNUmakefile @@ -56,9 +56,6 @@ SOGo_HEADER_FILES = \ SOGoGroup.h \ SOGoUser.h \ \ - NSDictionary+BSJSONAdditions.h \ - NSScanner+BSJSONAdditions.h \ - \ DOMNode+SOGo.h \ \ WORequest+SOGo.h \ @@ -121,9 +118,6 @@ SOGo_OBJC_FILES = \ SOGoGroup.m \ SOGoUser.m \ \ - NSDictionary+BSJSONAdditions.m \ - NSScanner+BSJSONAdditions.m \ - \ DOMNode+SOGo.m \ \ WORequest+SOGo.m \ diff --git a/SoObjects/SOGo/GNUmakefile.preamble b/SoObjects/SOGo/GNUmakefile.preamble index afd4c9796..1a6ce6544 100644 --- a/SoObjects/SOGo/GNUmakefile.preamble +++ b/SoObjects/SOGo/GNUmakefile.preamble @@ -13,14 +13,14 @@ SOGo_LIBRARIES_DEPEND_UPON += \ -L../../OGoContentStore/$(GNUSTEP_OBJ_DIR)/ \ -L../../SOPE/NGCards/$(GNUSTEP_OBJ_DIR)/ \ -lmemcached \ - -lOGoContentStore \ -lGDLAccess \ -lNGObjWeb \ -lNGCards \ -lNGMime \ -lNGStreams -lNGExtensions -lEOControl \ -lXmlRpc -lDOM -lSaxObjC -lcrypt \ - -lNGLdap + -lNGLdap -lSBJson \ + -lGDLContentStore ADDITIONAL_TOOL_LIBS += \ -L$(GNUSTEP_OBJ_DIR)/ \ diff --git a/SoObjects/SOGo/NSDictionary+BSJSONAdditions.h b/SoObjects/SOGo/NSDictionary+BSJSONAdditions.h deleted file mode 100644 index 5d34e045d..000000000 --- a/SoObjects/SOGo/NSDictionary+BSJSONAdditions.h +++ /dev/null @@ -1,43 +0,0 @@ -// -// BSJSONAdditions -// -// Created by Blake Seely on 2/1/06. -// Copyright 2006 Blake Seely - http://www.blakeseely.com All rights reserved. -// Permission to use this code: -// -// Feel free to use this code in your software, either as-is or -// in a modified form. Either way, please include a credit in -// your software's "About" box or similar, mentioning at least -// my name (Blake Seely). -// -// Permission to redistribute this code: -// -// You can redistribute this code, as long as you keep these -// comments. You can also redistribute modified versions of the -// code, as long as you add comments to say that you've made -// modifications (keeping these original comments too). -// -// If you do use or redistribute this code, an email would be -// appreciated, just to let me know that people are finding my -// code useful. You can reach me at blakeseely@mac.com - -#import - -extern NSString *jsonIndentString; -extern const int jsonDoNotIndent; - -@interface NSDictionary (BSJSONAdditions) - -- (NSString *)jsonStringValue; - -@end - -@interface NSDictionary (PrivateBSJSONAdditions) - -- (NSString *)jsonStringValueWithIndentLevel:(int)level; -- (NSString *)jsonStringForValue:(id)value withIndentLevel:(int)level; -- (NSString *)jsonStringForArray:(NSArray *)array withIndentLevel:(int)level; -- (NSString *)jsonStringForString:(NSString *)string; -- (NSString *)jsonIndentStringForLevel:(int)level; - -@end diff --git a/SoObjects/SOGo/NSDictionary+BSJSONAdditions.m b/SoObjects/SOGo/NSDictionary+BSJSONAdditions.m deleted file mode 100644 index 147493ee4..000000000 --- a/SoObjects/SOGo/NSDictionary+BSJSONAdditions.m +++ /dev/null @@ -1,190 +0,0 @@ -// -// BSJSONAdditions -// -// Created by Blake Seely on 2/1/06. -// Copyright 2006 Blake Seely - http://www.blakeseely.com All rights reserved. -// Permission to use this code: -// -// Feel free to use this code in your software, either as-is or -// in a modified form. Either way, please include a credit in -// your software's "About" box or similar, mentioning at least -// my name (Blake Seely). -// -// Permission to redistribute this code: -// -// You can redistribute this code, as long as you keep these -// comments. You can also redistribute modified versions of the -// code, as long as you add comments to say that you've made -// modifications (keeping these original comments too). -// -// If you do use or redistribute this code, an email would be -// appreciated, just to let me know that people are finding my -// code useful. You can reach me at blakeseely@mac.com - -#import -#import -#import -#import -#import - -#import "NSDictionary+BSJSONAdditions.h" -#import "NSScanner+BSJSONAdditions.h" - -NSString *jsonIndentString = @"\t"; // Modify this string to change how the output formats. -const int jsonDoNotIndent = -1; - -@implementation NSDictionary (BSJSONAdditions) - -- (NSString *)jsonStringValue -{ - return [self jsonStringValueWithIndentLevel:0]; -} - -@end - -@implementation NSDictionary (PrivateBSJSONAdditions) - -- (NSString *)jsonStringValueWithIndentLevel:(int)level -{ - NSMutableString *jsonString = [[NSMutableString alloc] init]; - [jsonString appendString:jsonObjectStartString]; - - NSEnumerator *keyEnum = [self keyEnumerator]; - NSString *keyString = [keyEnum nextObject]; - NSString *valueString; - if (keyString != nil) { - valueString = [self jsonStringForValue:[self objectForKey:keyString] withIndentLevel:level]; - if (level != jsonDoNotIndent) { // indent before each key - [jsonString appendString:[self jsonIndentStringForLevel:level]]; - } - [jsonString appendFormat:@" %@ %@ %@", [self jsonStringForString:keyString], jsonKeyValueSeparatorString, valueString]; - } - - while ((keyString = [keyEnum nextObject])) { - valueString = [self jsonStringForValue:[self objectForKey:keyString] withIndentLevel:level]; // TODO bail if valueString is nil? How to bail successfully from here? - [jsonString appendString:jsonValueSeparatorString]; - if (level != jsonDoNotIndent) { // indent before each key - [jsonString appendFormat:@"%@", [self jsonIndentStringForLevel:level]]; - } - [jsonString appendFormat:@" %@ %@ %@", [self jsonStringForString:keyString], jsonKeyValueSeparatorString, valueString]; - } - - //[jsonString appendString:@"\n"]; - [jsonString appendString:jsonObjectEndString]; - - return [jsonString autorelease]; -} - -- (NSString *)jsonStringForValue:(id)value withIndentLevel:(int)level -{ - NSString *jsonString; - if ([value respondsToSelector:@selector(characterAtIndex:)]) // String - jsonString = [self jsonStringForString:(NSString *)value]; - else if ([value respondsToSelector:@selector(keyEnumerator)]) // Dictionary - jsonString = [(NSDictionary *)value jsonStringValueWithIndentLevel:(level + 1)]; - else if ([value respondsToSelector:@selector(objectAtIndex:)]) // Array - jsonString = [self jsonStringForArray:(NSArray *)value withIndentLevel:level]; - else if (value == [NSNull null]) // null - jsonString = jsonNullString; - else if ([value respondsToSelector:@selector(objCType)]) { // NSNumber - representing true, false, and any form of numeric - NSNumber *number = (NSNumber *)value; - const char *t = [number objCType]; - if (((*t == 'c') || *t == 'C') && ([number boolValue] == YES)) // true - jsonString = jsonTrueString; - else if (((*t == 'c') || *t == 'C') && ([number boolValue] == NO)) // false - jsonString = jsonFalseString; - else // attempt to handle as a decimal number - int, fractional, exponential - // TODO: values converted from exponential json to dict and back to json do not format as exponential again - jsonString = [[NSDecimalNumber decimalNumberWithDecimal:[number decimalValue]] stringValue]; - } else { - // TODO: error condition - it's not any of the types that I know about. - return nil; - } - - return jsonString; -} - -- (NSString *)jsonStringForArray:(NSArray *)array withIndentLevel:(int)level -{ - NSMutableString *jsonString = [[NSMutableString alloc] init]; - [jsonString appendString:jsonArrayStartString]; - - if ([array count] > 0) { - [jsonString appendString:[self jsonStringForValue:[array objectAtIndex:0] withIndentLevel:level]]; - } - - int i; - for (i = 1; i < [array count]; i++) { - [jsonString appendFormat:@"%@ %@", jsonValueSeparatorString, [self jsonStringForValue:[array objectAtIndex:i] withIndentLevel:level]]; - } - - [jsonString appendString:jsonArrayEndString]; - return [jsonString autorelease]; -} - -- (NSString *)jsonStringForString:(NSString *)string -{ - NSMutableString *jsonString = [[NSMutableString alloc] init]; - [jsonString appendString:jsonStringDelimiterString]; - - // Build the result one character at a time, inserting escaped characters as necessary - int i; - unichar nextChar; - for (i = 0; i < [string length]; i++) { - nextChar = [string characterAtIndex:i]; - switch (nextChar) { - case '\"': - [jsonString appendString:@"\\\""]; - break; - case '\\': - [jsonString appendString:@"\\\\"]; - break; - /* TODO: email out to json group on this - spec says to handlt his, examples and example code don't handle this. - case '\/': - [jsonString appendString:@"\\/"]; - break; - */ - case '\b': - [jsonString appendString:@"\\b"]; - break; - case '\f': - [jsonString appendString:@"\\f"]; - break; - case '\n': - [jsonString appendString:@"\\n"]; - break; - case '\r': - [jsonString appendString:@"\\r"]; - break; - case '\t': - [jsonString appendString:@"\\t"]; - break; - /* TODO: Find and encode unicode characters here? - case '\u': - [jsonString appendString:@"\\n"]; - break; - */ - default: - [jsonString appendString:[NSString stringWithCharacters:&nextChar length:1]]; - break; - } - } - [jsonString appendString:jsonStringDelimiterString]; - return [jsonString autorelease]; -} - -- (NSString *)jsonIndentStringForLevel:(int)level -{ - NSMutableString *indentString = [[NSMutableString alloc] init]; - if (level != jsonDoNotIndent) { - [indentString appendString:@"\n"]; - int i; - for (i = 0; i < level; i++) { - [indentString appendString:jsonIndentString]; - } - } - - return [indentString autorelease]; -} - -@end diff --git a/SoObjects/SOGo/NSScanner+BSJSONAdditions.h b/SoObjects/SOGo/NSScanner+BSJSONAdditions.h deleted file mode 100644 index 88059178e..000000000 --- a/SoObjects/SOGo/NSScanner+BSJSONAdditions.h +++ /dev/null @@ -1,64 +0,0 @@ -// -// BSJSONAdditions -// -// Created by Blake Seely on 2/1/06. -// Copyright 2006 Blake Seely - http://www.blakeseely.com All rights reserved. -// Permission to use this code: -// -// Feel free to use this code in your software, either as-is or -// in a modified form. Either way, please include a credit in -// your software's "About" box or similar, mentioning at least -// my name (Blake Seely). -// -// Permission to redistribute this code: -// -// You can redistribute this code, as long as you keep these -// comments. You can also redistribute modified versions of the -// code, as long as you add comments to say that you've made -// modifications (keeping these original comments too). -// -// If you do use or redistribute this code, an email would be -// appreciated, just to let me know that people are finding my -// code useful. You can reach me at blakeseely@mac.com -// - -#import - -@class NSArray; -@class NSDictionary; -@class NSNumber; -@class NSString; - -extern NSString *jsonObjectStartString; -extern NSString *jsonObjectEndString; -extern NSString *jsonArrayStartString; -extern NSString *jsonArrayEndString; -extern NSString *jsonKeyValueSeparatorString; -extern NSString *jsonValueSeparatorString; -extern NSString *jsonStringDelimiterString; -extern NSString *jsonStringEscapedDoubleQuoteString; -extern NSString *jsonStringEscapedSlashString; -extern NSString *jsonTrueString; -extern NSString *jsonFalseString; -extern NSString *jsonNullString; - - -@interface NSScanner (PrivateBSJSONAdditions) - -- (BOOL)scanJSONObject:(NSMutableDictionary **)dictionary; -- (BOOL)scanJSONArray:(NSArray **)array; -- (BOOL)scanJSONString:(NSString **)string; -- (BOOL)scanJSONValue:(id *)value; -- (BOOL)scanJSONNumber:(NSNumber **)number; - -- (BOOL)scanJSONWhiteSpace; -- (BOOL)scanJSONKeyValueSeparator; -- (BOOL)scanJSONValueSeparator; -- (BOOL)scanJSONObjectStartString; -- (BOOL)scanJSONObjectEndString; -- (BOOL)scanJSONArrayStartString; -- (BOOL)scanJSONArrayEndString; -- (BOOL)scanJSONArrayEndString; -- (BOOL)scanJSONStringDelimiterString; - -@end diff --git a/SoObjects/SOGo/NSScanner+BSJSONAdditions.m b/SoObjects/SOGo/NSScanner+BSJSONAdditions.m deleted file mode 100644 index 2e653b875..000000000 --- a/SoObjects/SOGo/NSScanner+BSJSONAdditions.m +++ /dev/null @@ -1,347 +0,0 @@ -// -// BSJSONAdditions -// -// Created by Blake Seely on 2/1/06. -// Copyright 2006 Blake Seely - http://www.blakeseely.com All rights reserved. -// Permission to use this code: -// -// Feel free to use this code in your software, either as-is or -// in a modified form. Either way, please include a credit in -// your software's "About" box or similar, mentioning at least -// my name (Blake Seely). -// -// Permission to redistribute this code: -// -// You can redistribute this code, as long as you keep these -// comments. You can also redistribute modified versions of the -// code, as long as you add comments to say that you've made -// modifications (keeping these original comments too). -// -// If you do use or redistribute this code, an email would be -// appreciated, just to let me know that people are finding my -// code useful. You can reach me at blakeseely@mac.com -// -// -// Version 1.2: Includes modifications by Bill Garrison: http://www.standardorbit.com , which included -// Unit Tests adapted from Jonathan Wight's CocoaJSON code: http://www.toxicsoftware.com -// I have included those adapted unit tests in this package. - -#include - -#import -#import -#import -#import - -#import "NSScanner+BSJSONAdditions.h" - -NSString *jsonObjectStartString = @"{"; -NSString *jsonObjectEndString = @"}"; -NSString *jsonArrayStartString = @"["; -NSString *jsonArrayEndString = @"]"; -NSString *jsonKeyValueSeparatorString = @":"; -NSString *jsonValueSeparatorString = @","; -NSString *jsonStringDelimiterString = @"\""; -NSString *jsonStringEscapedDoubleQuoteString = @"\\\""; -NSString *jsonStringEscapedSlashString = @"\\\\"; -NSString *jsonTrueString = @"true"; -NSString *jsonFalseString = @"false"; -NSString *jsonNullString = @"null"; - -@implementation NSScanner (PrivateBSJSONAdditions) - -- (BOOL)scanJSONObject:(NSMutableDictionary **)dictionary -{ - //[self setCharactersToBeSkipped:nil]; - - BOOL result = NO; - - /* START - April 21, 2006 - Updated to bypass irrelevant characters at the beginning of a JSON string */ - NSString *ignoredString; - [self scanUpToString:jsonObjectStartString intoString:&ignoredString]; - /* END - April 21, 2006 */ - - if (![self scanJSONObjectStartString]) { - // TODO: Error condition. For now, return false result, do nothing with the dictionary handle - } else { - NSMutableDictionary *jsonKeyValues = [[[NSMutableDictionary alloc] init] autorelease]; - NSString *key = nil; - id value; - [self scanJSONWhiteSpace]; - while (([self scanJSONString:&key]) && ([self scanJSONKeyValueSeparator]) && ([self scanJSONValue:&value])) { - [jsonKeyValues setObject:value forKey:key]; - [self scanJSONWhiteSpace]; - // check to see if the character at scan location is a value separator. If it is, do nothing. - if ([[[self string] substringWithRange:NSMakeRange([self scanLocation], 1)] isEqualToString:jsonValueSeparatorString]) { - [self scanJSONValueSeparator]; - } - } - if ([self scanJSONObjectEndString]) { - // whether or not we found a key-val pair, we found open and close brackets - completing an object - result = YES; - *dictionary = jsonKeyValues; - } - } - return result; -} - -- (BOOL)scanJSONArray:(NSArray **)array -{ - BOOL result = NO; - NSMutableArray *values = [[[NSMutableArray alloc] init] autorelease]; - [self scanJSONArrayStartString]; - id value = nil; - - while ([self scanJSONValue:&value]) { - [values addObject:value]; - [self scanJSONWhiteSpace]; - if ([[[self string] substringWithRange:NSMakeRange([self scanLocation], 1)] isEqualToString:jsonValueSeparatorString]) { - [self scanJSONValueSeparator]; - } - } - if ([self scanJSONArrayEndString]) { - result = YES; - *array = values; - } - - return result; -} - -- (BOOL)scanJSONString:(NSString **)string -{ - BOOL result = NO; - if ([self scanJSONStringDelimiterString]) { - NSMutableString *chars = [[[NSMutableString alloc] init] autorelease]; - NSString *characterFormat = @"%C"; - - // process character by character until we finish the string or reach another double-quote - while ((![self isAtEnd]) && ([[self string] characterAtIndex:[self scanLocation]] != '\"')) { - unichar currentChar = [[self string] characterAtIndex:[self scanLocation]]; - unichar nextChar; - if (currentChar != '\\') { - [chars appendFormat:characterFormat, currentChar]; - [self setScanLocation:([self scanLocation] + 1)]; - } else { - nextChar = [[self string] characterAtIndex:([self scanLocation] + 1)]; - switch (nextChar) { - case '\"': - [chars appendString:@"\""]; - [self setScanLocation:([self scanLocation] + 2)]; - break; - case '\\': - [chars appendString:@"\\"]; // debugger shows result as having two slashes, but final output is correct. Possible debugger error? - [self setScanLocation:([self scanLocation] + 2)]; - break; - /* TODO: json.org docs mention this seq, so does yahoo, but not recognized here by xcode, note from crockford: not a required escape - case '\/': - [chars appendString:@"\/"]; - [self setScanLocation:([self scanLocation] + 2)]; - break; - */ - case 'b': - [chars appendString:@"\b"]; - [self setScanLocation:([self scanLocation] + 2)]; - break; - case 'f': - [chars appendString:@"\f"]; - [self setScanLocation:([self scanLocation] + 2)]; - break; - case 'n': - [chars appendString:@"\n"]; - [self setScanLocation:([self scanLocation] + 2)]; - break; - case 'r': - [chars appendString:@"\r"]; - [self setScanLocation:([self scanLocation] + 2)]; - break; - case 't': - [chars appendString:@"\t"]; - [self setScanLocation:([self scanLocation] + 2)]; - break; - case 'u': // unicode sequence - get string of hex chars, convert to int, convert to unichar, append - [self setScanLocation:([self scanLocation] + 2)]; // advance past '\u' - NSString *digits = [[self string] substringWithRange:NSMakeRange([self scanLocation], 4)]; - /* START Updated code modified from code fix submitted by Bill Garrison - March 28, 2006 - http://www.standardorbit.net */ - NSScanner *hexScanner = [NSScanner scannerWithString:digits]; - NSString *verifiedHexDigits; - NSCharacterSet *hexDigitSet = [NSCharacterSet characterSetWithCharactersInString:@"0123456789ABCDEFabcdef"]; - if (NO == [hexScanner scanCharactersFromSet:hexDigitSet intoString:&verifiedHexDigits]) - return NO; - if (4 != [verifiedHexDigits length]) - return NO; - - // Read in the hex value - [hexScanner setScanLocation:0]; - unsigned unicodeHexValue; - if (NO == [hexScanner scanHexInt:&unicodeHexValue]) { - return NO; - } - [chars appendFormat:characterFormat, unicodeHexValue]; - /* END update - March 28, 2006 */ - [self setScanLocation:([self scanLocation] + 4)]; - break; - default: - [chars appendFormat:@"\\%C", nextChar]; - [self setScanLocation:([self scanLocation] + 2)]; - break; - } - } - } - - if (![self isAtEnd]) { - result = [self scanJSONStringDelimiterString]; - *string = chars; - } - - return result; - - /* this code is more appropriate if you have a separate method to unescape the found string - for example, between inputting json and outputting it, it may make more sense to have a category on NSString to perform - escaping and unescaping. Keeping this code and looking into this for a future update. - unsigned int searchLength = [[self string] length] - [self scanLocation]; - unsigned int quoteLocation = [[self string] rangeOfString:jsonStringDelimiterString options:0 range:NSMakeRange([self scanLocation], searchLength)].location; - searchLength = [[self string] length] - quoteLocation; - while (([[[self string] substringWithRange:NSMakeRange((quoteLocation - 1), 2)] isEqualToString:jsonStringEscapedDoubleQuoteString]) && - (quoteLocation != NSNotFound) && - (![[[self string] substringWithRange:NSMakeRange((quoteLocation -2), 2)] isEqualToString:jsonStringEscapedSlashString])){ - searchLength = [[self string] length] - (quoteLocation + 1); - quoteLocation = [[self string] rangeOfString:jsonStringDelimiterString options:0 range:NSMakeRange((quoteLocation + 1), searchLength)].location; - } - - *string = [[self string] substringWithRange:NSMakeRange([self scanLocation], (quoteLocation - [self scanLocation]))]; - // TODO: process escape sequences out of the string - replacing with their actual characters. a function that does just this belongs - // in another class. So it may make more sense to change this whole implementation to just go character by character instead. - [self setScanLocation:(quoteLocation + 1)]; - */ - result = YES; - - } - - return result; -} - -- (BOOL)scanJSONValue:(id *)value -{ - BOOL result = NO; - - [self scanJSONWhiteSpace]; - NSString *substring = [[self string] substringWithRange:NSMakeRange([self scanLocation], 1)]; - NSUInteger trueLocation = [[self string] rangeOfString:jsonTrueString options:0 range:NSMakeRange([self scanLocation], ([[self string] length] - [self scanLocation]))].location; - NSUInteger falseLocation = [[self string] rangeOfString:jsonFalseString options:0 range:NSMakeRange([self scanLocation], ([[self string] length] - [self scanLocation]))].location; - NSUInteger nullLocation = [[self string] rangeOfString:jsonNullString options:0 range:NSMakeRange([self scanLocation], ([[self string] length] - [self scanLocation]))].location; - - if ([substring isEqualToString:jsonStringDelimiterString]) { - result = [self scanJSONString:value]; - } else if ([substring isEqualToString:jsonObjectStartString]) { - result = [self scanJSONObject:value]; - } else if ([substring isEqualToString:jsonArrayStartString]) { - result = [self scanJSONArray:value]; - } else if ([self scanLocation] == trueLocation) { - result = YES; - *value = [NSNumber numberWithBool:YES]; - [self setScanLocation:([self scanLocation] + [jsonTrueString length])]; - } else if ([self scanLocation] == falseLocation) { - result = YES; - *value = [NSNumber numberWithBool:NO]; - [self setScanLocation:([self scanLocation] + [jsonFalseString length])]; - } else if ([self scanLocation] == nullLocation) { - result = YES; - *value = [NSNull null]; - [self setScanLocation:([self scanLocation] + [jsonNullString length])]; - } else if (([[NSCharacterSet decimalDigitCharacterSet] characterIsMember:[[self string] characterAtIndex:[self scanLocation]]]) || - ([[self string] characterAtIndex:[self scanLocation]] == '-')){ // check to make sure it's a digit or - - result = [self scanJSONNumber:value]; - } - return result; -} - -- (BOOL)scanJSONNumber:(NSNumber **)number -{ - //NSDecimal decimal; - //BOOL result = [self scanDecimal:&decimal]; - //*number = [NSDecimalNumber decimalNumberWithDecimal:decimal]; - long long intValue, commaValue; - double doubleValue; - NSUInteger curLocation, length; - NSString *stringValue; - - stringValue = [self string]; - - BOOL result = [self scanLongLong: &intValue]; - if (result) - { - curLocation = [self scanLocation]; - if (curLocation < [stringValue length] - && [stringValue characterAtIndex: curLocation] == '.') - { - [self scanString: @"." intoString: NULL]; - if ([self scanLongLong: &commaValue]) - { - result = YES; - length = [self scanLocation] - curLocation - 1; - if (intValue < 0) - commaValue = -commaValue; - doubleValue = intValue + commaValue / pow(10.0, length); - *number = [NSNumber numberWithDouble: doubleValue]; - } - else - *number = [NSNumber numberWithLongLong: intValue]; - } - else - *number = [NSNumber numberWithLongLong: intValue]; - } - else - *number = nil; - - return result; -} - -- (BOOL)scanJSONWhiteSpace -{ - //NSLog(@"Scanning white space - here are the next ten chars ---%@---", [[self string] substringWithRange:NSMakeRange([self scanLocation], 10)]); - BOOL result = NO; - NSCharacterSet *space = [NSCharacterSet whitespaceAndNewlineCharacterSet]; - while ([space characterIsMember:[[self string] characterAtIndex:[self scanLocation]]]) { - [self setScanLocation:([self scanLocation] + 1)]; - result = YES; - } - //NSLog(@"Done Scanning white space - here are the next ten chars ---%@---", [[self string] substringWithRange:NSMakeRange([self scanLocation], 10)]); - return result; -} - -- (BOOL)scanJSONKeyValueSeparator -{ - return [self scanString:jsonKeyValueSeparatorString intoString:NULL]; -} - -- (BOOL)scanJSONValueSeparator -{ - return [self scanString:jsonValueSeparatorString intoString:NULL]; -} - -- (BOOL)scanJSONObjectStartString -{ - return [self scanString:jsonObjectStartString intoString:NULL]; -} - -- (BOOL)scanJSONObjectEndString -{ - return [self scanString:jsonObjectEndString intoString:NULL]; -} - -- (BOOL)scanJSONArrayStartString -{ - return [self scanString:jsonArrayStartString intoString:NULL]; -} - -- (BOOL)scanJSONArrayEndString -{ - return [self scanString:jsonArrayEndString intoString:NULL]; -} - -- (BOOL)scanJSONStringDelimiterString; -{ - return [self scanString:jsonStringDelimiterString intoString:NULL]; -} - -@end diff --git a/SoObjects/SOGo/NSString+Utilities.m b/SoObjects/SOGo/NSString+Utilities.m index 0e37d761e..df13789e8 100644 --- a/SoObjects/SOGo/NSString+Utilities.m +++ b/SoObjects/SOGo/NSString+Utilities.m @@ -29,12 +29,13 @@ #import #import +#import #import +#import + #import "NSArray+Utilities.h" -#import "NSDictionary+BSJSONAdditions.h" #import "NSDictionary+URL.h" -#import "NSScanner+BSJSONAdditions.h" #import "NSString+Utilities.h" @@ -513,21 +514,28 @@ static NSMutableCharacterSet *safeLDIFStartChars = nil; - (id) objectFromJSONString { - NSScanner *scanner; + SBJsonParser *parser; NSObject *object; + NSError *error; object = nil; if ([self length] > 0) { - scanner = [[NSScanner alloc] initWithString: self]; - if (![scanner scanJSONValue: &object]) - object = nil; - [scanner autorelease]; + parser = [SBJsonParser new]; + [parser autorelease]; + error = nil; + object = [parser objectWithString: self + error: &error]; + if (error) + { + [self errorWithFormat: @"json parser: %@", error]; + [self errorWithFormat: @"original string is: %@", self]; + object = nil; + } } return object; } - @end diff --git a/SoObjects/SOGo/SOGoCASSession.m b/SoObjects/SOGo/SOGoCASSession.m index dbefa1683..9104dbe03 100644 --- a/SoObjects/SOGo/SOGoCASSession.m +++ b/SoObjects/SOGo/SOGoCASSession.m @@ -35,7 +35,7 @@ #import #import -#import "NSDictionary+BSJSONAdditions.h" +#import "NSDictionary+Utilities.h" #import "NSString+Utilities.h" #import "SOGoCache.h" #import "SOGoObject.h" @@ -167,7 +167,7 @@ [sessionDict setObject: identifier forKey: @"identifier"]; if ([proxyTickets count]) [sessionDict setObject: proxyTickets forKey: @"proxyTickets"]; - jsonSession = [sessionDict jsonStringValue]; + jsonSession = [sessionDict jsonRepresentation]; [cache setCASSession: jsonSession withTicket: ticket forIdentifier: identifier]; diff --git a/SoObjects/SOGo/SOGoCache.m b/SoObjects/SOGo/SOGoCache.m index e2e25b5c8..457de6d83 100644 --- a/SoObjects/SOGo/SOGoCache.m +++ b/SoObjects/SOGo/SOGoCache.m @@ -48,7 +48,7 @@ #import #import -#import "NSDictionary+BSJSONAdditions.h" +#import "NSDictionary+Utilities.h" #import "NSString+Utilities.h" #import "SOGoObject.h" #import "SOGoSystemDefaults.h" @@ -484,7 +484,7 @@ static memcached_st *handle = NULL; forPath: (NSString *) thePath { if (theACLs) - [self _cacheValues: [theACLs jsonStringValue] + [self _cacheValues: [theACLs jsonRepresentation] ofType: @"acl" forKey: thePath]; else diff --git a/SoObjects/SOGo/SOGoDomainDefaults.h b/SoObjects/SOGo/SOGoDomainDefaults.h index 73b7bb13a..48b87dac8 100644 --- a/SoObjects/SOGo/SOGoDomainDefaults.h +++ b/SoObjects/SOGo/SOGoDomainDefaults.h @@ -41,6 +41,7 @@ - (NSString *) mailDomain; - (NSString *) imapServer; +- (NSString *) sieveServer; - (NSString *) imapAclStyle; - (NSString *) imapFolderSeparator; - (BOOL) imapAclConformsToIMAPExt; diff --git a/SoObjects/SOGo/SOGoDomainDefaults.m b/SoObjects/SOGo/SOGoDomainDefaults.m index d445348c7..1b9dc4fe0 100644 --- a/SoObjects/SOGo/SOGoDomainDefaults.m +++ b/SoObjects/SOGo/SOGoDomainDefaults.m @@ -113,6 +113,11 @@ return [self stringForKey: @"SOGoIMAPServer"]; } +- (NSString *) sieveServer +{ + return [self stringForKey: @"SOGoSieveServer"]; +} + #warning should be removed when we make use of imap namespace - (NSString *) imapAclStyle { diff --git a/SoObjects/SOGo/SOGoUserManager.m b/SoObjects/SOGo/SOGoUserManager.m index 274bc9ee7..d98edd1fd 100644 --- a/SoObjects/SOGo/SOGoUserManager.m +++ b/SoObjects/SOGo/SOGoUserManager.m @@ -30,8 +30,8 @@ #import #import "NSArray+Utilities.h" -#import "NSDictionary+BSJSONAdditions.h" #import "NSString+Utilities.h" +#import "NSObject+Utilities.h" #import "SOGoDomainDefaults.h" #import "SOGoSource.h" #import "SOGoSystemDefaults.h" @@ -440,7 +440,7 @@ // internal cache. [currentUser setObject: _pwd forKey: @"password"]; [[SOGoCache sharedCache] - setUserAttributes: [currentUser jsonStringValue] + setUserAttributes: [currentUser jsonRepresentation] forLogin: _login]; } else @@ -481,7 +481,7 @@ // internal cache. [currentUser setObject: newPassword forKey: @"password"]; [[SOGoCache sharedCache] - setUserAttributes: [currentUser jsonStringValue] + setUserAttributes: [currentUser jsonRepresentation] forLogin: login]; } else @@ -595,13 +595,13 @@ key = [newUser objectForKey: @"c_uid"]; if (key) [[SOGoCache sharedCache] - setUserAttributes: [newUser jsonStringValue] + setUserAttributes: [newUser jsonRepresentation] forLogin: key]; emails = [[newUser objectForKey: @"emails"] objectEnumerator]; while ((key = [emails nextObject])) [[SOGoCache sharedCache] - setUserAttributes: [newUser jsonStringValue] + setUserAttributes: [newUser jsonRepresentation] forLogin: key]; } diff --git a/SoObjects/SOGo/SOGoUserProfile.m b/SoObjects/SOGo/SOGoUserProfile.m index 27d07f6a7..87d0b2c2c 100644 --- a/SoObjects/SOGo/SOGoUserProfile.m +++ b/SoObjects/SOGo/SOGoUserProfile.m @@ -21,6 +21,7 @@ */ #import +#import #import #import @@ -30,7 +31,6 @@ #import "NSObject+Utilities.h" #import "NSString+Utilities.h" -#import "NSDictionary+BSJSONAdditions.h" #import "SOGoCache.h" #import "SOGoUserProfile.h" @@ -139,7 +139,7 @@ { [self logWithFormat: @"database value for %@" @" (uid: '%@') is a plist", [self profileTypeName], uid]; - jsonValue = [plist jsonStringValue]; + jsonValue = [plist jsonRepresentation]; } else { @@ -223,7 +223,7 @@ SOGoCache *cache; BOOL rc; - jsonRepresentation = [values jsonStringValue]; + jsonRepresentation = [values jsonRepresentation]; if (jsonRepresentation) { rc = [self storeJSONProfileInDB: jsonRepresentation]; diff --git a/SoObjects/common.make b/SoObjects/common.make index aa2cb9da2..0232c3894 100644 --- a/SoObjects/common.make +++ b/SoObjects/common.make @@ -32,6 +32,6 @@ BUNDLE_LIBS += \ -lNGObjWeb \ -lNGCards -lNGMime -lNGLdap \ -lNGStreams -lNGExtensions -lEOControl \ - -lXmlRpc -lDOM -lSaxObjC + -lXmlRpc -lDOM -lSaxObjC -lSBJson ADDITIONAL_BUNDLE_LIBS += $(BUNDLE_LIBS) diff --git a/Tests/Integration/GNUmakefile b/Tests/Integration/GNUmakefile new file mode 100644 index 000000000..5c8baad1d --- /dev/null +++ b/Tests/Integration/GNUmakefile @@ -0,0 +1,19 @@ +PROGRAM=teststrings + +SRCS=teststrings.m +OBJS=$(SRCS:.m=.o) + +teststrings: $(OBJS) + $(CC) -o $@ $< $(GNUSTEP_LIBRARIES_FLAGS) -lgnustep-base -L../../SoObjects/SOGo/SOGo.framework -lSOGo + +include $(GNUSTEP_MAKEFILES)/common.make + +all: $(PROGRAM) + +clean: + rm -f $(PROGRAM) $(OBJS) *~ + +.m.o: + $(CC) -o $@ -c $(GNUSTEP_HEADERS_FLAGS) $(AUXILIARY_OBJCFLAGS) $(OBJCFLAGS) $(CPPFLAGS) -I../../SoObjects $< + +.SUFFIXES: .m .o diff --git a/Tests/Integration/teststrings.m b/Tests/Integration/teststrings.m new file mode 100644 index 000000000..6ae5f979e --- /dev/null +++ b/Tests/Integration/teststrings.m @@ -0,0 +1,79 @@ +/* teststrings.m - this file is part of SOGO + * + * Copyright (C) 2010 Inverse inc. + * + * Author: Wolfgang Sourdeau + * + * 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 + +#import + +static int +performTest (char *filename) +{ + NSDictionary *testDict; + NSString *nsFilename; + int rc; + + nsFilename = [NSString stringWithFormat: @"%s", filename]; + NS_DURING + { + testDict = [NSDictionary dictionaryFromStringsFile: nsFilename]; + if ([testDict count] == 0) + { + NSLog (@"Bad or empty strings file"); + rc = 2; + testDict = nil; + } + else + rc = 0; + } + NS_HANDLER + { + NSLog (@"An exception was caught: %@", localException); + rc = 1; + testDict = nil; + } + NS_ENDHANDLER; + + return rc; +} + +int +main (int argc, char *argv[]) +{ + NSAutoreleasePool *pool; + int rc; + + pool = [NSAutoreleasePool new]; + + if (argc == 2) + { + rc = performTest (argv[1]); + } + else + { + NSLog (@"Usage: %s file.strings", argv[0]); + rc = 1; + } + + [pool release]; + + return rc; +} diff --git a/Tests/Integration/teststrings.sh b/Tests/Integration/teststrings.sh new file mode 100755 index 000000000..d531e4ed6 --- /dev/null +++ b/Tests/Integration/teststrings.sh @@ -0,0 +1,20 @@ +#!/bin/sh + +TOPDIR=../.. + +if [ ! -f teststrings ] +then + make teststrings +fi + +for stringfile in ${TOPDIR}/*/*/*.lproj/Localizable.strings +do + ./teststrings "$stringfile" > /dev/null + code=$? + if test $code -eq 0; + then + echo "$stringfile: passed"; + else + echo "$stringfile: failed (code: $code)"; + fi +done diff --git a/UI/Contacts/GNUmakefile b/UI/Contacts/GNUmakefile index ec7177f8c..90c97a79d 100644 --- a/UI/Contacts/GNUmakefile +++ b/UI/Contacts/GNUmakefile @@ -15,6 +15,7 @@ ContactsUI_OBJC_FILES = \ \ ContactsUIProduct.m \ UIxContactsFilterPanel.m \ + UIxContactActions.m \ UIxContactView.m \ UIxContactEditor.m \ UIxListView.m \ diff --git a/UI/Contacts/UIxContactActions.m b/UI/Contacts/UIxContactActions.m new file mode 100644 index 000000000..03f5f6a07 --- /dev/null +++ b/UI/Contacts/UIxContactActions.m @@ -0,0 +1,131 @@ +/* UIxContactActions.m - this file is part of SOGo + * + * Copyright (C) 2010 Inverse inc. + * + * Author: Wolfgang Sourdeau + * + * 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 +#import + +#import +#import + +#import + +#import + +#import + +@interface NGVCard (SOGoActionCategory) + +- (BOOL) addOrRemove: (BOOL) set + category: (NSString *) newCategory; + +@end + +@implementation NGVCard (SOGoActionCategory) + +- (BOOL) addOrRemove: (BOOL) set + category: (NSString *) category +{ + NSMutableArray *categories; + BOOL modified; + NSUInteger idx; + + modified = NO; + + categories = [[self categories] mutableCopy]; + [categories autorelease]; + if (set) + { + if (![categories containsObject: category]) + { + [categories addObject: category]; + modified = YES; + } + } + else + { + idx = [categories indexOfObject: category]; + if (idx != NSNotFound) + { + [categories removeObjectAtIndex: idx]; + modified = YES; + } + } + + if (modified) + [self setCategories: categories]; + + return modified; +} + +@end + +@interface UIxContactActions : WODirectAction + +- (WOResponse *) setCategoryAction; +- (WOResponse *) unsetCategoryAction; + +@end + +@implementation UIxContactActions + +- (WOResponse *) _setOrUnsetCategoryAction: (BOOL) set +{ + SOGoContactGCSEntry *contact; + NSString *category; + WORequest *rq; + WOResponse *response; + NGVCard *card; + + rq = [context request]; + category = [rq formValueForKey: @"category"]; + if ([category length] > 0) + { + contact = [self clientObject]; + if (![contact isNew]) + { + card = [contact vCard]; + if ([card addOrRemove: set category: category]) + [contact save]; + response = [self responseWith204]; + } + else + response = [self responseWithStatus: 404 + andString: @"Contact does not exist"]; + } + else + response = [self responseWithStatus: 403 + andString: @"Missing 'category' parameter"]; + + return response; +} + +- (WOResponse *) setCategoryAction +{ + return [self _setOrUnsetCategoryAction: YES]; +} + +- (WOResponse *) unsetCategoryAction +{ + return [self _setOrUnsetCategoryAction: NO]; +} + +@end diff --git a/UI/Contacts/product.plist b/UI/Contacts/product.plist index 945c9a136..2136af2bf 100644 --- a/UI/Contacts/product.plist +++ b/UI/Contacts/product.plist @@ -184,6 +184,16 @@ pageName = "UIxContactEditor"; actionName = "write"; }; + setCategory = { + protectedBy = "Change Images And Files"; + actionClass = "UIxContactActions"; + actionName = "setCategory"; + }; + unsetCategory = { + protectedBy = "Change Images And Files"; + actionClass = "UIxContactActions"; + actionName = "unsetCategory"; + }; }; }; diff --git a/UI/MailPartViewers/UIxMailPartHTMLViewer.m b/UI/MailPartViewers/UIxMailPartHTMLViewer.m index 7fde4ba8b..3581bbcad 100644 --- a/UI/MailPartViewers/UIxMailPartHTMLViewer.m +++ b/UI/MailPartViewers/UIxMailPartHTMLViewer.m @@ -1,6 +1,6 @@ /* UIxMailPartHTMLViewer.m - this file is part of SOGo * - * Copyright (C) 2007-2009 Inverse inc. + * Copyright (C) 2007-2010 Inverse inc. * * Author: Wolfgang Sourdeau * diff --git a/UI/PreferencesUI/UIxPreferences.m b/UI/PreferencesUI/UIxPreferences.m index 77893bc63..555b9228d 100644 --- a/UI/PreferencesUI/UIxPreferences.m +++ b/UI/PreferencesUI/UIxPreferences.m @@ -33,7 +33,6 @@ #import #import -#import #import #import #import @@ -659,9 +658,7 @@ [capabilities retain]; } - return [[NSDictionary dictionary] - jsonStringForArray: capabilities - withIndentLevel: 0]; + return [capabilities jsonRepresentation]; } - (BOOL) isVacationEnabled @@ -683,9 +680,7 @@ - (NSString *) sieveFiltersValue { - return [[NSDictionary dictionary] - jsonStringForArray: sieveFilters - withIndentLevel: 0]; + return [sieveFilters jsonRepresentation]; } - (void) setEnableVacation: (BOOL) enableVacation diff --git a/UI/Templates/ContactsUI/UIxContactFoldersView.wox b/UI/Templates/ContactsUI/UIxContactFoldersView.wox index 318d811cd..2bd9210cc 100644 --- a/UI/Templates/ContactsUI/UIxContactFoldersView.wox +++ b/UI/Templates/ContactsUI/UIxContactFoldersView.wox @@ -7,6 +7,7 @@ xmlns:uix="OGo:uix" xmlns:label="OGo:label" xmlns:rsrc="OGo:url" + const:userDefaultsKeys="SOGoContactsCategories" className="UIxPageFrame" title="name" var:popup="isPopup"> @@ -72,6 +73,7 @@