From 0df0e340739e12983e98a97e668dd3cf713327cf Mon Sep 17 00:00:00 2001 From: Hivert Quentin Date: Thu, 2 Nov 2023 17:19:14 +0100 Subject: [PATCH] doc(sogo-tool): Add doc to detailed sogo-tool --- Documentation/SOGoInstallationGuide.asciidoc | 483 +++++++++++++++++++ Tools/SOGoToolCheckupUser.m | 140 +++--- Tools/SOGoToolExpireUserSessions.m | 2 + Tools/SOGoToolManageACL.m | 10 +- Tools/SOGoToolRemoveDoubles.m | 115 +++-- Tools/SOGoToolRestore.m | 2 +- Tools/SOGoToolTruncateCalendar.m | 6 +- Tools/sogo-tool.m | 3 + 8 files changed, 632 insertions(+), 129 deletions(-) diff --git a/Documentation/SOGoInstallationGuide.asciidoc b/Documentation/SOGoInstallationGuide.asciidoc index 13e0e46a0..ebcd50f82 100644 --- a/Documentation/SOGoInstallationGuide.asciidoc +++ b/Documentation/SOGoInstallationGuide.asciidoc @@ -3312,6 +3312,489 @@ any mobile devices that support Microsoft ActiveSync. Microsoft Outlook The Microsoft ActiveSync server URL is generally something like: `http://127.0.0.1/Microsoft-Server-ActiveSync`. +Using sogo-tool +--------------- +The command _sogo-tool_ allows to do some operations on database and sieve filter. It is included with +the sogo package on Debian/Ubuntu but must be installed manually on RHEl/CentOS: + + yum install sogo-tool + +*_WARNING_: Use sogo-tool with full awareness of what you are doing. This is an admin tool that can cause loss of data +or completely make the webmail unusable by a user.* + +sogo-tool backup/restore +~~~~~~~~~~~~~~~~~~~~~~~~ + +The backup tool saves the information of a user into a file. The information saved are its preferences, its events and its contacts. + + sogo-tool backup directory ALL|user1 [user2] ... + +* First argument, *directory* must be a path, only the last subdirectory will be created, the previous ones must exist. +* Second argument is *ALL* to backup all users or put each user space-separated. +* Each user's info will take one file, the filename will be the username. +* The files are readable but in a specific format for _sogo-tool restore_. + +Example: +---- +sogo-tool backup /tmp/foo ALL # Will save all users into /tmp/foo +sogo-tool backup /etc/sogo_backup/foo user1 user2 # Will save only user1 and user2. The directory /etc/sogo_backup must exist. +---- + +Using the files produced by the backup, you can restore all or some information of a user with the _restore_ command: + + sogo-tool restore [-l|-p|-f/-F folder/ALL] [-c credentialFile] directory user + +* First argument must be one of the four mode options *-l*, *-p*, *-f* or *-F*. +* Second, optional, is *-c* with the credential file. Only useful with *-p* mode. +* *directory* is the path where the backup file is. +* *user* is the name of the backup file, which is the username if you use the _backup_ tool. + +The differents mode are: + +* *-l* will only list the folders (meaning calendar and address book) that would be restored with *-f* or *-F*. + +Example: +---- +sogo-tool restore -l /tmp/backup user1 +---- +Result: +---- +Calendar/60C8-65323D80-7-4D9F7D80 (new_calendar) +Calendar/personal (Personal Calendar) +Contacts/personal (Personal Address Book) +---- + +* *-p* will restore the user's preferences. If the user has an active sieve script (filter, vacation, forward...) you must provide a credential file with +the parameters *-c*. The credential file is a simple one-line file that contains the "username:password" of an admin account of your imap/sieve server. + +Example: +---- +sogo-tool restore -p /tmp/backup user1 +sogo-tool restore -p -c /var/sogo/cred /tmp/backup user1 +---- + +* *-f* will restore the events/contacts of folders (calendar and address book) from the backup file that don't exist in the database. If the event/contact +was deleted but is in the backup file, it will be restored. If the event/contact exist, nothing will be done even if it has been modified compared to the +backup file. If a whole folder has been deleted but is in the backup file, it will be restored. *-f* expect a value that can be ALL to restore all folders, +or the name of the folder to restore. You can list them with the *-l* mode. + +Example: +---- +sogo-tool restore -f ALL /tmp/backup user1 +sogo-tool restore -f "Contacts/personal" tmp/backup user1 +sogo-tool restore -f "Calendar/60C8-65323D80-7-4D9F7D80" tmp/backup user1 +---- +The commands will either prints out nothing or any events/contacts restored: +---- +restoring record '60CA-65323D00-1-680B0A00.ics' +restoring record '60C8-65323D00-1-4D9F7D80.vcf' +restoring record '60C8-65323D80-9-4D9F7D80.ics' +---- + +* *-F* has the same behavior as *-f* but it will first delete all contacts and events in database before restoring the backup. +So if an event/contact is not in the backup file, it will be lost. If a folder exists but is not in the backup file, nothing will happen +to it and its content. + +*-F* expect a value that can be ALL to restore all folders, or the name of the folder to restore. You can list them with the *-l* mode. + +Example: +---- +sogo-tool restore -F ALL /tmp/backup user1 +sogo-tool restore -F "Contacts/personal" tmp/backup user1 +sogo-tool restore -F "Calendar/60C8-65323D80-7-4D9F7D80" tmp/backup user1 +---- + +sogo-tool checkup +~~~~~~~~~~~~~~~~~ + +Check the events and contacts data's integrity of a user + + sogo-tool checkup [-d] user... + +* *-d*, optional, will delete all corrupted data. +* *user* is a single username or multiple user each space-separated. + +Will print out nothing if no corrupted data were found or one of the following messages: + +* Corrupted calendar item (missing tags) in path with c_name = +* Corrupted calendar item (unparsable) in path with c_name = +* Missing start date of event in path with c_name = ()" +* Missing end date of event in path with c_name = ()" +* Start date () is not before end date () for event in path with c_name = () +* Corrupted card item (unparsable) in path with c_name = + +It can also print log from SOGo if it raise errors: + +* <0x0x55e0956c4d00[VSCardSaxDriver]> serious inconsistency among begin/end tags + +Example: +---- +sogo-tool checkup user1 +sogo-tool checkup -d user1 +---- + +sogo-tool cleanup +~~~~~~~~~~~~~~~~~ + +Will purge all user's deleted events and contacts which the deletion is older than a number of days. + + sogo-tool cleanup [days] ALL|user1 [user2] + +* *days* the age of deleted records to purge in days +* Second argument is *ALL* to purge events of all users or put each user space-separated. + +Example: +---- +sogo-tool cleanup 30 ALL +sogo-tool cleanup 30 user1 user2 +---- +Outputs: +---- +Purged 3 records from folder /Users/user1/Calendar/60C7-65325300-9-18F39AA0 +Purged 1 records from folder /Users/user1/Calendar/60C8-65323D80-7-4D9F7D80 +Purged 0 records from folder /Users/user1/Calendar/personal +Purged 0 records from folder /Users/user1/Contacts/personal +Purged 5 records from folder /Users/user2/Calendar/personal +---- + + +sogo-tool create-folder +~~~~~~~~~~~~~~~~~~~~~~~ + +Create a folder (Calendar or Address Book) for a user. + + create-folder user type [displayname ...] + +* *user* is the name of the user +* *type* is either "Calendar" or "Contacts" +* *displayname* is the folder's name. If the name is already taken, a new folder will still be made but with another uid. + +Example: +---- +sogo-tool create-folder user1 Contacts Pro_Contacts Ext_Contacts +sogo-tool create-folder user2 Calendar Pro_Calendar +---- + + +sogo-tool dump-defaults +~~~~~~~~~~~~~~~~~~~~~~~ + +Output all current defaults value of GNUstep and SOGo (sogo.conf) + + sogo-tool dump-defaults [-f |[all]] + +* Can be used without arguments and will output the defaults for gnustep domain 'sogod'. +* *all* option will output all defaults value found from sogo and gnustep in property list format. +* *-f* expect a filepath of an .xml file and will output it in property list format (sogo.conf). May need some tweaks, though. + +Example: +---- +sogo-tool dump-defaults +sogo-tool dump-defaults all +sogo-tool dump-defaults -f /tmp/foo/conf.xml +---- + +sogo-tool expire-sessions +~~~~~~~~~~~~~~~~~~~~~~~~~ + +Expires user sessions from database without activity for specified number of minutes. When a user log in to sogo for +the first time, sogo will create a entry in database's table OCSSessionsFolderURL with the user's information. Sogo will +also set a cookie with an encoded value to fetch this database table. That way, each time the user make a request with that cookie, +sogo will know which connected user it is. This command will remove all user's session from database +without activity for specified number of minutes. Those users will have to log in again. + + sogo-tool expire-sessions [nbMinutes] + +* *nbMinutes* Integer, number of minutes. All session without activity in these last minutes will be removed. +* _*Warning*_ Putting anything other that a number will be count as 0 minutes... + +Example: +---- +sogo-tool expire-sessions #Will print usage. +sogo-tool expire-sessions 160 #Will remove session which last activity is older than 160 minutes. +sogo-tool expire-sessions --help #Will remove session which last activity is older than 0 minutes. +---- + +sogo-tool manage-acl +~~~~~~~~~~~~~~~~~~~~ + +Manage access-control list (ACL) of a user for folders (Calendar and Address Book). + + sogo-tool manage-acl get|add|remove|subscribe|unsubscribe owner folder user|group + +* First argument is the action among *get*, *add*, *remove*, *subscribe* and *unsubscribe*. +* Second argument is the username of the folder's owner. +* Third argument is the name of the folder. +* Fourth argument is the user whom to manage its acl. It also can be _ALL_, _anonymous_ and __. +* Fifth argument, only needed with *add* action, is the rights to set for the user. + +The actions: + +* *get* will print out the folder's rights of the user or nothing if the user is not found or doesn't have any rights. + +Example: +---- +sogo-tool manage-acl get sogo-tests1 Calendar/5E1F-653FC400-1-38155940 sogo-tests2 +---- +Result: +---- +Rights for sogo-tests2 ["PublicModifier", "ConfidentialModifier", "PrivateModifier", "ObjectCreator", "ObjectEraser"] +---- + +* *add* will add the given rights to the user for the given folder. the value right is a json string of an array with each right to set. +Be Careful as there is no check for the rights already set. It could be better to first remove them, then add them. + +The rights for Address Book are: + +* _ObjectCreator_: can create cards (contact of list) +* _ObjectEditor_: can modify cards +* _ObjectViewer_: can view cards +* _ObjectEraser_: can delete cards + +The rights for Calendar are: + +* _ObjectCreator_: can create event or task +* _ObjectEraser_: can delete event or task +* __ can be _Public_, _Confidential_ or _Private_ +* _Viewer_: can view the whole events (ex: PrivateViewer) +* _DAndTViewer_: can only view the date and time of events +* _Modifier_: can view and edit the events +* _Responder_: can view the events + +Example: +---- +sogo-tool manage-acl add sogo-tests1 Contacts/5E1D-653FC400-1-1A330C40 sogo-tests2 '["ObjectViewer", "ObjectEraser"]' +---- + +* *remove* all user's rights to the folder. + +Example: +---- +sogo-tool manage-acl remove sogo-tests1 Contacts/5E1D-653FC400-1-1A330C40 sogo-tests2 +---- + +* *subscribe* the user to the folder. + +Example: +---- +sogo-tool manage-acl subscribe sogo-tests1 Contacts/5E1D-653FC400-1-1A330C40 sogo-tests2 +---- + +* *unsubscribe* the user to the folder. + +Example: +---- +sogo-tool manage-acl unsubscribe sogo-tests1 Contacts/5E1D-653FC400-1-1A330C40 sogo-tests2 +---- + +sogo-tool manage-eas +~~~~~~~~~~~~~~~~~~~~ + +Manage EAS folders + + sogo-tool manage-eas listdevices|listfolders|resetdevice|resetfolder|mergevcard|mergevevent user + +* First argument is the action among *listdevices*, *listfolders*, *resetdevice*, *resetfolder*, *mergevcard* and *mergevevent*. +* Second argument is the *user* whom to perform the action. +* Third argument is the *deviceId* of, if the action is *resetFolder*, the *folderId*. No need of this argument if the action is *listdevices* +* Fourth argument, only use with *mergevcard* and *mergevevent* is either YES to merge and *NO* to un-merge. + +The actions: + +* *listdevices*: list the devices belonging to user. +* *listfolders*: list all folders of deviceId for user. +* *resetdevice*: force deviceId of user to resync everything. +* *resetfolder*: force folderId of user to resync everything. +* *mergevcard*: merge/un-merge all addressbooks into one for deviceId of user. +* *mergevevent*: merge/un-merge all calendars into one for deviceId of user. + +Examples: +---- +sogo-tool manage-eas listdevices janedoe +sogo-tool manage-eas listfolders janedoe androidc316986417 +sogo-tool manage-eas resetdevice janedoe androidc316986417 +sogo-tool manage-eas resetfolder janedow androidc316986417 folderlala-dada-sasa_7a13_1a2386e0_e +sogo-tool manage-eas mergevcard janedow androidc316986417 YES +sogo-tool manage-eas mergevevent janedow androidc316986417 YES +---- + +sogo-tool remove +~~~~~~~~~~~~~~~~ + +Remove all folders (Calendar and Address Book) and Preference settings of a user. The personal Calendar and Address Book +will stay but be emptied of all entries. The Preferences will go back to defaults values as for a new user. + + sogo-tool remove user1 [user2] + +* Arguments one user or several space-separated. +* You can add -v after sogo*tool to list all removed folders + +Example: +---- +sogo-tool remove user1 +sogo-tool -v remove user2 +---- +Output example with -v options: +---- +Deleting /Users/user2/Calendar/B088-65363400-3-2B9DF0C0 +Deleting /Users/user2/Calendar/personal +Deleting /Users/user2/Contacts/B087-65363380-5-374DA380 +Deleting /Users/user2/Contacts/B087-65363400-7-374DA380 +Deleting /Users/user2/Contacts/personal +---- + +sogo-tool remove-doubles +~~~~~~~~~~~~~~~~~~~~~~~~ + +remove duplicate contacts from the specified user addressbook + + sogo-tool remove-doubles USER FOLDER + +* *USER* is the name of the user to perform the removal +* *FOLDER* is the name of the folder to clean from duplicates + +Two contacts are considered duplicates when they have the same mails or display name. When two or more contacts +are duplicates, each one will get a score. The ones with the highest score will be kept and the others +will be discarded. If two records have the same score, the first one to have reach it will be kept. +The scores are distributed as such: +* Record which has been the last modified: +1 +* Record has the most content: +2 +* Record has the most quick field set: +3 +* Record is in a contact list: +6 + +Example: +---- +sogo-tool remove-doubles user1 personal +sogo-tool remove-doubles user2 489-65376E80-1-2D2BA000 +---- + +sogo-tool rename-user +~~~~~~~~~~~~~~~~~~~~~ + +Update records pertaining to a user after a change of user id. Will change all folders path, subscriptions from others users, +all mention of user id in database. + + sogo-tool rename-user fromuserid touserid + +* *fromuserid* Previous user id +* *touserid* New user id + +If the new user id already exist, the command will output a message and do nothing. +**WARNING** This command only change database of sogo, if you use ldap or others databases they will still keep the old id. + +Example: +---- +sogo-tool rename-user old_username new_username +---- + +sogo-tool truncate-calendar +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Remove old calendar entries from the specified user calendar. + + sogo-tool truncate-calendar [-r] USER FOLDER DATE + +* *-r* optional, to also delete recurrent events that have occurrence after *DATE* +* *USER* is the name of the owner of the calendar +* *FOLDER* is the name of the calendar folder to clean up +* *DATE* UTC datetime, event older than this date will be removed + +Without *-r*, only reccurrent events which all occurrences are older than *DATE* will be removed. +With *-r*, event the if there are occurrences after *DATE*, the recurrent event will be removed. +*DATE* can take the value `date +%FT%T` which is the current time + +Example: +---- +sogo-tool truncate-calendar sogo-tests1 personal 2023-10-25T00:00:00 +sogo-tool truncate-calendar -r sogo-tests2 5E38-6538BE80-5-AFF8310 2022-01-01T15:30:00 +sogo-tool truncate-calendar -r sogo-tests2 personal `date +%FT%T` #will delete all event older than now +---- +Result: +---- +No record to remove. All records kept. +---- +---- +Removing 1 records... +Removed 1 records. +---- + +sogo-tool update-autoreply +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +_This command is only useful if your sieve server doesn't have the capabilities *date* or *relational*_ +In that case this command will check vacation's setting of all the users. If vacation is enabled/disabled, +the starting and ending date, the body and others parameters. If needed, the command +will write the sieve script accordingly. + + sogo-tool update-autoreply -p credentialFile + +* *-p- The credential file, a simple one-line file that contains "username:password" of an admin account of your imap/sieve server. + +Example: +---- + sogo-tool update-autoreply -p /var/sogo/cred +---- + +sogo-tool user-preferences +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Get, set or unset user defaults / settings in the database. + +_Settings_ stores parameters for user's calendar, mail and contacts. It can be graphic +as month view or week view for calendar but it also stores subscription, delegation... +It also stores the private Salt for TOTP and the parameter ForceResetPassword to force the +user to change password. + +_Defaults_ stores all parameters that can be found in Preferences panel. So it goes from default language to +autoreply to many others options. + + + user-preferences get|set|unset defaults|settings user key [value|-f filename] [-p credentialFile] + +* First argument is the action *get*, *set* or *unset* +* Second argument is parameter type *settings* or *defaults* +* Third argument *user* is the name of the user where to make the action +* Fourth argument *key* is the name of the parameters where to make the action +* If the action is *set*, you should provide either *value* as fifth argument or a file with the value inside with *-f* filename/path +* If the action is *set* or *unset* and the *key* concerns a sieve script (filter, vacation, forward...), you +should provide a credential file, a one-line file that contains "username:password" of an admin account of your imap/sieve server. + +As there is a lot of parameters, this documentation will not go into details for each one. To know what are +the key names and their value you should got to your database in table defined by _SOGoProfileURL_ in your sogo.conf. +Here, for each row (user) you will find c_defaults and c_settings which are json with the keys. However, if +a parameter has never been set, it won't appears in those json. The clean way to know the missing keys is to +set it up in one of your dummy/dev/test account then see the values in _SOGoProfileURL_. Be careful, a value +can be a json itself, only the primary key can be get/set/unset. + +Example with forwarding, *get* action: +---- +sogo-tool user-preferences get defaults user1 Forward +---- +If forward has never been set the result will be: +---- +Value for key "Forward" not found in defaults +---- +Else it will be +---- +{"forwardAddress":["sogo-tests2@sogo.alinto"],"enabled":1,"keepCopy":1} +---- + +*unset* action: +---- +sogo-tool user-preferences unset defaults user1 Forward -p /etc/sogo/cred +---- + +*set* action: +---- +sogo-tool user-preferences set defaults user1 Forward '{"forwardAddress":["sogo-tests2@sogo.alinto"],"enabled":1,"keepCopy":0}' -p cred +---- +or create a json file which contains _{"forwardAddress":["sogo-tests2@sogo.alinto"],"enabled":1,"keepCopy":0}_ then: +---- +sogo-tool user-preferences set defaults user1 Forward -f /path/filename -p cred +---- + + + Upgrading --------- diff --git a/Tools/SOGoToolCheckupUser.m b/Tools/SOGoToolCheckupUser.m index 1c0939bfb..cfc0e5d00 100644 --- a/Tools/SOGoToolCheckupUser.m +++ b/Tools/SOGoToolCheckupUser.m @@ -221,95 +221,95 @@ count = [objects count]; for (i = 0; i < count; i++) - { - content = [[[objects objectAtIndex: i] objectForKey: @"c_content"] stringByTrimmingSpaces]; - c_name = [[objects objectAtIndex: i] objectForKey: @"c_name"]; - if (is_calendar) - { - // We check for - // BEGIN:VCALENDAR - // .. - // END:VCALENDAR - iCalCalendar *calendar; + { + content = [[[objects objectAtIndex: i] objectForKey: @"c_content"] stringByTrimmingSpaces]; + c_name = [[objects objectAtIndex: i] objectForKey: @"c_name"]; + if (is_calendar) + { + // We check for + // BEGIN:VCALENDAR + // .. + // END:VCALENDAR + iCalCalendar *calendar; - if ([content length] < 30 || + if ([content length] < 30 || [[content substringToIndex: 15] caseInsensitiveCompare: @"BEGIN:VCALENDAR"] != NSOrderedSame || [[content substringFromIndex: [content length]-13] caseInsensitiveCompare: @"END:VCALENDAR"] != NSOrderedSame) { NSLog(@"Corrupted calendar item (missing tags) in path %@ with c_name = %@", folder, c_name); if (delete) - [gcsFolder deleteContentWithName: c_name]; + [gcsFolder deleteContentWithName: c_name]; rc = NO; } - else + else { calendar = [iCalCalendar parseSingleFromSource: content]; if (!calendar) - { - NSLog(@"Corrupted calendar item (unparsable) in path %@ with c_name = %@", folder, c_name); - if (delete) - [gcsFolder deleteContentWithName: c_name]; - rc = NO; - } - else - { - iCalEvent *event; + { + NSLog(@"Corrupted calendar item (unparsable) in path %@ with c_name = %@", folder, c_name); + if (delete) + [gcsFolder deleteContentWithName: c_name]; + rc = NO; + } + else + { + iCalEvent *event; - event = (iCalEvent *) [calendar firstChildWithTag: @"vevent"]; - if (event) - { - iCalDateTime *startDate, *endDate; + event = (iCalEvent *) [calendar firstChildWithTag: @"vevent"]; + if (event) + { + iCalDateTime *startDate, *endDate; - startDate = (iCalDateTime *) [event uniqueChildWithTag: @"dtstart"]; - if (![startDate dateTime]) - { - NSLog(@"Missing start date of event in path %@ with c_name = %@ (%@)", folder, c_name, [event summary]); - if (delete) - [gcsFolder deleteContentWithName: c_name]; - rc = NO; - } - endDate = (iCalDateTime *) [event uniqueChildWithTag: @"dtend"]; - if (![endDate dateTime] && ![event hasDuration]) - { - NSLog(@"Missing end date of event in path %@ with c_name = %@ (%@)", folder, c_name, [event summary]); - if (delete) - [gcsFolder deleteContentWithName: c_name]; - rc = NO; - } - if ([startDate dateTime] && [endDate dateTime]) - { - NSComparisonResult comparison; + startDate = (iCalDateTime *) [event uniqueChildWithTag: @"dtstart"]; + if (![startDate dateTime]) + { + NSLog(@"Missing start date of event in path %@ with c_name = %@ (%@)", folder, c_name, [event summary]); + if (delete) + [gcsFolder deleteContentWithName: c_name]; + rc = NO; + } + endDate = (iCalDateTime *) [event uniqueChildWithTag: @"dtend"]; + if (![endDate dateTime] && ![event hasDuration]) + { + NSLog(@"Missing end date of event in path %@ with c_name = %@ (%@)", folder, c_name, [event summary]); + if (delete) + [gcsFolder deleteContentWithName: c_name]; + rc = NO; + } + if ([startDate dateTime] && [endDate dateTime]) + { + NSComparisonResult comparison; - comparison = [[startDate dateTime] compare: [endDate dateTime]]; - if (([event isAllDay] && comparison == NSOrderedDescending) || - (![event isAllDay] && comparison != NSOrderedAscending)) - { - NSLog(@"Start date (%@) is not before end date (%@) for event in path %@ with c_name = %@ (%@)", - [startDate dateTime], [endDate dateTime], folder, c_name, [event summary]); - if (delete) - [gcsFolder deleteContentWithName: c_name]; - rc = NO; - } - } - } - } + comparison = [[startDate dateTime] compare: [endDate dateTime]]; + if (([event isAllDay] && comparison == NSOrderedDescending) || + (![event isAllDay] && comparison != NSOrderedAscending)) + { + NSLog(@"Start date (%@) is not before end date (%@) for event in path %@ with c_name = %@ (%@)", + [startDate dateTime], [endDate dateTime], folder, c_name, [event summary]); + if (delete) + [gcsFolder deleteContentWithName: c_name]; + rc = NO; + } + } + } + } } - } - else - { - NGVCard *card; + } + else + { + NGVCard *card; - card = [NGVCard parseSingleFromSource: content]; + card = [NGVCard parseSingleFromSource: content]; - if (!card) + if (!card) { - NSLog(@"Corrupted card item (unparsable) in path %@ with c_name = %@", folder, c_name); - if (delete) - [gcsFolder deleteContentWithName: c_name]; - rc = NO; + NSLog(@"Corrupted card item (unparsable) in path %@ with c_name = %@", folder, c_name); + if (delete) + [gcsFolder deleteContentWithName: c_name]; + rc = NO; } - } - } + } + } return rc; } diff --git a/Tools/SOGoToolExpireUserSessions.m b/Tools/SOGoToolExpireUserSessions.m index 63cfb47f0..aeedc00e9 100644 --- a/Tools/SOGoToolExpireUserSessions.m +++ b/Tools/SOGoToolExpireUserSessions.m @@ -138,6 +138,8 @@ sessionExpireMinutes = [[arguments objectAtIndex: 0] intValue]; } + NSLog(@"Remove all sessions older than %d min", sessionExpireMinutes); + if (sessionExpireMinutes >= 0) { rc = [self expireUserSessionOlderThan: sessionExpireMinutes]; diff --git a/Tools/SOGoToolManageACL.m b/Tools/SOGoToolManageACL.m index 914ec528e..a9de6d62e 100644 --- a/Tools/SOGoToolManageACL.m +++ b/Tools/SOGoToolManageACL.m @@ -113,13 +113,13 @@ typedef enum " remove remove all ACL information of folder for user\n" " subscribe subscribe user to owner's folder\n" " unsubscribe unsubscribe user to owner's folder\n" - " owner the user owning the folder\n" + " owner the user owning the folder\n" " folder the folder - Calendar/ or Contacts/\n" " user the user (or group without the @ prefix) to get/set rights for - 'ALL', '', 'anonymous' are supported\n" - " rights rights to add\n\n" - "Example: sogo-tool manage-acl get jdoe Calendar/personal ALL\n\n" - "Note: You can add only one access right at the time. To set them all at once,\n" - " invoke 'remove' first to remove them all.\n\n"); + " rights rights to add\n\n" + "Example: sogo-tool manage-acl get jdoe Calendar/personal ALL\n\n" + "Note: You can add only one access right at the time. To set them all at once,\n" + " invoke 'remove' first to remove them all.\n\n"); } - (BOOL) parseArguments diff --git a/Tools/SOGoToolRemoveDoubles.m b/Tools/SOGoToolRemoveDoubles.m index 7a188a55c..809f67f7f 100644 --- a/Tools/SOGoToolRemoveDoubles.m +++ b/Tools/SOGoToolRemoveDoubles.m @@ -86,15 +86,15 @@ /* we want to match the field value case-insensitively */ recordEmail = [[record objectForKey: field] uppercaseString]; if ([recordEmail length]) + { + recordList = [doubleEmails objectForKey: recordEmail]; + if (!recordList) { - recordList = [doubleEmails objectForKey: recordEmail]; - if (!recordList) - { - recordList = [NSMutableArray arrayWithCapacity: 5]; - [doubleEmails setObject: recordList forKey: recordEmail]; - } - [recordList addObject: record]; + recordList = [NSMutableArray arrayWithCapacity: 5]; + [doubleEmails setObject: recordList forKey: recordEmail]; } + [recordList addObject: record]; + } } - (void) cleanupSingleRecords: (NSMutableDictionary *) doubleEmails @@ -220,21 +220,20 @@ recordsToRemove = [NSMutableArray arrayWithCapacity: (max - 1)]; for (count = 0; count < max; count++) + { + if (count != keptRecord) { - if (count != keptRecord) - { - currentRecord = [records objectAtIndex: count]; - [recordsToRemove - addObject: [currentRecord objectForKey: @"c_name"]]; - } + currentRecord = [records objectAtIndex: count]; + [recordsToRemove addObject: [currentRecord objectForKey: @"c_name"]]; } + } return recordsToRemove; } - (NSArray *) records: (NSArray *) records withLowestScores: (unsigned int *) scores - count: (unsigned int) max + count: (unsigned int) max { unsigned int count, highestScore; int highestScoreRecord; @@ -242,13 +241,13 @@ highestScore = 0; highestScoreRecord = -1; for (count = 0; count < max; count++) + { + if (scores[count] > highestScore) { - if (scores[count] > highestScore) - { - highestScore = scores[count]; - highestScoreRecord = count; - } + highestScore = scores[count]; + highestScoreRecord = count; } + } if (highestScoreRecord == -1) highestScoreRecord = 0; @@ -268,16 +267,15 @@ highestVersion = 0; for (count = 0; count < max; count++) + { + currentVersion = [[records objectAtIndex: count] objectForKey: @"c_version"]; + version = [currentVersion intValue]; + if (version > highestVersion) { - currentVersion - = [[records objectAtIndex: count] objectForKey: @"c_version"]; - version = [currentVersion intValue]; - if (version > highestVersion) - { - mostModified = count; - highestVersion = version; - } + mostModified = count; + highestVersion = version; } + } return mostModified; } @@ -291,25 +289,25 @@ amount = 0; if (!quickFields) - { - quickFields = [NSArray arrayWithObjects: @"c_givenname", @"c_cn", - @"c_sn", @"c_screenname", @"c_l", @"c_mail", - @"c_o", @"c_ou", @"c_telephonenumber", nil]; - [quickFields retain]; - } + { + quickFields = [NSArray arrayWithObjects: @"c_givenname", @"c_cn", + @"c_sn", @"c_screenname", @"c_l", @"c_mail", + @"c_o", @"c_ou", @"c_telephonenumber", nil]; + [quickFields retain]; + } max = [quickFields count]; for (count = 0; count < max; count++) + { + value = [record objectForKey: [quickFields objectAtIndex: count]]; + if ([value isKindOfClass: [NSString class]]) { - value = [record objectForKey: [quickFields objectAtIndex: count]]; - if ([value isKindOfClass: [NSString class]]) - { - if ([value length]) - amount++; - } - else if ([value isKindOfClass: [NSNumber class]]) - amount++; + if ([value length]) + amount++; } + else if ([value isKindOfClass: [NSNumber class]]) + amount++; + } return amount; } @@ -323,15 +321,14 @@ highestQFields = 0; for (count = 0; count < max; count++) + { + currentQFields = [self amountOfFilledQuickFields: [records objectAtIndex: count]]; + if (currentQFields > highestQFields) { - currentQFields - = [self amountOfFilledQuickFields: [records objectAtIndex: count]]; - if (currentQFields > highestQFields) - { - mostQuickFields = count; - highestQFields = currentQFields; - } + mostQuickFields = count; + highestQFields = currentQFields; } + } return mostQuickFields; } @@ -399,10 +396,28 @@ } - (void) assignScores: (unsigned int *) scores - toRecords: (NSArray *) records - count: (unsigned int) max + toRecords: (NSArray *) records + count: (unsigned int) max withCardsInLists: (NSArray *) cardsInLists { + /* + Records is an Array of record which are duplicates of each other. + The goal here is to know which one to keep and whoch ones to discard. + We will assign a score to each record, the one with the best scores is kept + Record which has been the last modified: +1 + Record has the most content: +2 + Record has the most quick field set: +3 + Record is in a list: +6 + + If two record have the same, for exemple, content. It's the first one on the list + that will get the points. + If two recors have the same score. t's the first one on the list + that will get the points. + + quick fiels are =("c_givenname": Firstname, @"c_cn": Display, + @"c_sn": LastName, @"c_screenname": Screen Name @"c_l": City, @"c_mail": mails, + @"c_o": organisation, @"c_ou": organisation unit, @"c_telephonenumber": telephone) + */ int recordIndex; recordIndex = [self mostModifiedRecord: records count: max]; diff --git a/Tools/SOGoToolRestore.m b/Tools/SOGoToolRestore.m index 5d57c889e..c2275bbf8 100644 --- a/Tools/SOGoToolRestore.m +++ b/Tools/SOGoToolRestore.m @@ -634,7 +634,7 @@ if (authname == nil || authpwd == nil) { - NSLog(@"To update Sieve scripts, you must provide the \"-p credentialFile\" parameter"); + NSLog(@"To update Sieve scripts, you must provide the \"-c credentialFile\" parameter"); return NO; } diff --git a/Tools/SOGoToolTruncateCalendar.m b/Tools/SOGoToolTruncateCalendar.m index 80857c676..e412adf37 100644 --- a/Tools/SOGoToolTruncateCalendar.m +++ b/Tools/SOGoToolTruncateCalendar.m @@ -210,8 +210,7 @@ GCSFolder *folder; BOOL rc; - folderPath = [NSString stringWithFormat: @"/Users/%@/Calendar/%@", - username, folderId]; + folderPath = [NSString stringWithFormat: @"/Users/%@/Calendar/%@", username, folderId]; folder = [fom folderAtPath: folderPath]; if (folder) rc = [self truncateEntriesFromFolder: folder usingDate: date]; @@ -238,12 +237,13 @@ // in the default timezone. s = [NSString stringWithFormat: @"%@ GMT", date]; d = [NSCalendarDate dateWithString: s calendarFormat: @"%Y-%m-%dT%H:%M:%S %Z"]; + NSLog(@"Date is: %@", d); fom = [GCSFolderManager defaultFolderManager]; if (d && fom) rc = [self processFolder: folder ofUser: username - date: d + date: d withFoM: fom]; else rc = NO; diff --git a/Tools/sogo-tool.m b/Tools/sogo-tool.m index b4314af10..b837d2a03 100644 --- a/Tools/sogo-tool.m +++ b/Tools/sogo-tool.m @@ -146,6 +146,9 @@ [helpString appendFormat: @"\t%-20@-- %@\n", command, [currentTool objectAtIndex: 1]]; } + [helpString appendString: @"\n Visit https://www.sogo.nu/files/docs/SOGoInstallationGuide.html#_using_sogo_tool to get more infos"]; + + NSLog (@"%@", helpString); }