doc(sogo-tool): Add doc to detailed sogo-tool

This commit is contained in:
Hivert Quentin
2023-11-02 17:19:14 +01:00
parent f41ab2ed0c
commit 0df0e34073
8 changed files with 632 additions and 129 deletions

View File

@@ -3312,6 +3312,489 @@ any mobile devices that support Microsoft ActiveSync. Microsoft Outlook
The Microsoft ActiveSync server URL is generally something The Microsoft ActiveSync server URL is generally something
like: `http://127.0.0.1/Microsoft-Server-ActiveSync`. 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 <path> with c_name = <ics_id>
* Corrupted calendar item (unparsable) in path <path> with c_name = <ics_id>
* Missing start date of event in path <path> with c_name = <ics_id> (<event_name>)"
* Missing end date of event in path <path> with c_name = <ics_id> (<event_name>)"
* Start date (<start_date>) is not before end date (<end_date>) for event in path <path> with c_name = <ics_id> (<event_name>)
* Corrupted card item (unparsable) in path <path> with c_name = <vcard_id>
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 <filename>|[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 <rights>
* 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 _<defaults>_.
* 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
* _<type>_ can be _Public_, _Confidential_ or _Private_
* _<type>Viewer_: can view the whole events (ex: PrivateViewer)
* _<type>DAndTViewer_: can only view the date and time of events
* _<type>Modifier_: can view and edit the events
* _<type>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 <deviceId | folderId> <YES | NO>
* 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 Upgrading
--------- ---------

View File

@@ -221,95 +221,95 @@
count = [objects count]; count = [objects count];
for (i = 0; i < count; i++) for (i = 0; i < count; i++)
{ {
content = [[[objects objectAtIndex: i] objectForKey: @"c_content"] stringByTrimmingSpaces]; content = [[[objects objectAtIndex: i] objectForKey: @"c_content"] stringByTrimmingSpaces];
c_name = [[objects objectAtIndex: i] objectForKey: @"c_name"]; c_name = [[objects objectAtIndex: i] objectForKey: @"c_name"];
if (is_calendar) if (is_calendar)
{ {
// We check for // We check for
// BEGIN:VCALENDAR // BEGIN:VCALENDAR
// .. // ..
// END:VCALENDAR // END:VCALENDAR
iCalCalendar *calendar; iCalCalendar *calendar;
if ([content length] < 30 || if ([content length] < 30 ||
[[content substringToIndex: 15] caseInsensitiveCompare: @"BEGIN:VCALENDAR"] != NSOrderedSame || [[content substringToIndex: 15] caseInsensitiveCompare: @"BEGIN:VCALENDAR"] != NSOrderedSame ||
[[content substringFromIndex: [content length]-13] caseInsensitiveCompare: @"END: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); NSLog(@"Corrupted calendar item (missing tags) in path %@ with c_name = %@", folder, c_name);
if (delete) if (delete)
[gcsFolder deleteContentWithName: c_name]; [gcsFolder deleteContentWithName: c_name];
rc = NO; rc = NO;
} }
else else
{ {
calendar = [iCalCalendar parseSingleFromSource: content]; calendar = [iCalCalendar parseSingleFromSource: content];
if (!calendar) if (!calendar)
{ {
NSLog(@"Corrupted calendar item (unparsable) in path %@ with c_name = %@", folder, c_name); NSLog(@"Corrupted calendar item (unparsable) in path %@ with c_name = %@", folder, c_name);
if (delete) if (delete)
[gcsFolder deleteContentWithName: c_name]; [gcsFolder deleteContentWithName: c_name];
rc = NO; rc = NO;
} }
else else
{ {
iCalEvent *event; iCalEvent *event;
event = (iCalEvent *) [calendar firstChildWithTag: @"vevent"]; event = (iCalEvent *) [calendar firstChildWithTag: @"vevent"];
if (event) if (event)
{ {
iCalDateTime *startDate, *endDate; iCalDateTime *startDate, *endDate;
startDate = (iCalDateTime *) [event uniqueChildWithTag: @"dtstart"]; startDate = (iCalDateTime *) [event uniqueChildWithTag: @"dtstart"];
if (![startDate dateTime]) if (![startDate dateTime])
{ {
NSLog(@"Missing start date of event in path %@ with c_name = %@ (%@)", folder, c_name, [event summary]); NSLog(@"Missing start date of event in path %@ with c_name = %@ (%@)", folder, c_name, [event summary]);
if (delete) if (delete)
[gcsFolder deleteContentWithName: c_name]; [gcsFolder deleteContentWithName: c_name];
rc = NO; rc = NO;
} }
endDate = (iCalDateTime *) [event uniqueChildWithTag: @"dtend"]; endDate = (iCalDateTime *) [event uniqueChildWithTag: @"dtend"];
if (![endDate dateTime] && ![event hasDuration]) if (![endDate dateTime] && ![event hasDuration])
{ {
NSLog(@"Missing end date of event in path %@ with c_name = %@ (%@)", folder, c_name, [event summary]); NSLog(@"Missing end date of event in path %@ with c_name = %@ (%@)", folder, c_name, [event summary]);
if (delete) if (delete)
[gcsFolder deleteContentWithName: c_name]; [gcsFolder deleteContentWithName: c_name];
rc = NO; rc = NO;
} }
if ([startDate dateTime] && [endDate dateTime]) if ([startDate dateTime] && [endDate dateTime])
{ {
NSComparisonResult comparison; NSComparisonResult comparison;
comparison = [[startDate dateTime] compare: [endDate dateTime]]; comparison = [[startDate dateTime] compare: [endDate dateTime]];
if (([event isAllDay] && comparison == NSOrderedDescending) || if (([event isAllDay] && comparison == NSOrderedDescending) ||
(![event isAllDay] && comparison != NSOrderedAscending)) (![event isAllDay] && comparison != NSOrderedAscending))
{ {
NSLog(@"Start date (%@) is not before end date (%@) for event in path %@ with c_name = %@ (%@)", NSLog(@"Start date (%@) is not before end date (%@) for event in path %@ with c_name = %@ (%@)",
[startDate dateTime], [endDate dateTime], folder, c_name, [event summary]); [startDate dateTime], [endDate dateTime], folder, c_name, [event summary]);
if (delete) if (delete)
[gcsFolder deleteContentWithName: c_name]; [gcsFolder deleteContentWithName: c_name];
rc = NO; rc = NO;
} }
} }
} }
} }
} }
} }
else else
{ {
NGVCard *card; 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); NSLog(@"Corrupted card item (unparsable) in path %@ with c_name = %@", folder, c_name);
if (delete) if (delete)
[gcsFolder deleteContentWithName: c_name]; [gcsFolder deleteContentWithName: c_name];
rc = NO; rc = NO;
} }
} }
} }
return rc; return rc;
} }

View File

@@ -138,6 +138,8 @@
sessionExpireMinutes = [[arguments objectAtIndex: 0] intValue]; sessionExpireMinutes = [[arguments objectAtIndex: 0] intValue];
} }
NSLog(@"Remove all sessions older than %d min", sessionExpireMinutes);
if (sessionExpireMinutes >= 0) if (sessionExpireMinutes >= 0)
{ {
rc = [self expireUserSessionOlderThan: sessionExpireMinutes]; rc = [self expireUserSessionOlderThan: sessionExpireMinutes];

View File

@@ -113,13 +113,13 @@ typedef enum
" remove remove all ACL information of folder for user\n" " remove remove all ACL information of folder for user\n"
" subscribe subscribe user to owner's folder\n" " subscribe subscribe user to owner's folder\n"
" unsubscribe unsubscribe 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/<ID> or Contacts/<ID>\n" " folder the folder - Calendar/<ID> or Contacts/<ID>\n"
" user the user (or group without the @ prefix) to get/set rights for - 'ALL', '<default>', 'anonymous' are supported\n" " user the user (or group without the @ prefix) to get/set rights for - 'ALL', '<default>', 'anonymous' are supported\n"
" rights rights to add\n\n" " rights rights to add\n\n"
"Example: sogo-tool manage-acl get jdoe Calendar/personal ALL\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" "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"); " invoke 'remove' first to remove them all.\n\n");
} }
- (BOOL) parseArguments - (BOOL) parseArguments

View File

@@ -86,15 +86,15 @@
/* we want to match the field value case-insensitively */ /* we want to match the field value case-insensitively */
recordEmail = [[record objectForKey: field] uppercaseString]; recordEmail = [[record objectForKey: field] uppercaseString];
if ([recordEmail length]) if ([recordEmail length])
{
recordList = [doubleEmails objectForKey: recordEmail];
if (!recordList)
{ {
recordList = [doubleEmails objectForKey: recordEmail]; recordList = [NSMutableArray arrayWithCapacity: 5];
if (!recordList) [doubleEmails setObject: recordList forKey: recordEmail];
{
recordList = [NSMutableArray arrayWithCapacity: 5];
[doubleEmails setObject: recordList forKey: recordEmail];
}
[recordList addObject: record];
} }
[recordList addObject: record];
}
} }
- (void) cleanupSingleRecords: (NSMutableDictionary *) doubleEmails - (void) cleanupSingleRecords: (NSMutableDictionary *) doubleEmails
@@ -220,21 +220,20 @@
recordsToRemove = [NSMutableArray arrayWithCapacity: (max - 1)]; recordsToRemove = [NSMutableArray arrayWithCapacity: (max - 1)];
for (count = 0; count < max; count++) 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; return recordsToRemove;
} }
- (NSArray *) records: (NSArray *) records - (NSArray *) records: (NSArray *) records
withLowestScores: (unsigned int *) scores withLowestScores: (unsigned int *) scores
count: (unsigned int) max count: (unsigned int) max
{ {
unsigned int count, highestScore; unsigned int count, highestScore;
int highestScoreRecord; int highestScoreRecord;
@@ -242,13 +241,13 @@
highestScore = 0; highestScore = 0;
highestScoreRecord = -1; highestScoreRecord = -1;
for (count = 0; count < max; count++) 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) if (highestScoreRecord == -1)
highestScoreRecord = 0; highestScoreRecord = 0;
@@ -268,16 +267,15 @@
highestVersion = 0; highestVersion = 0;
for (count = 0; count < max; count++) for (count = 0; count < max; count++)
{
currentVersion = [[records objectAtIndex: count] objectForKey: @"c_version"];
version = [currentVersion intValue];
if (version > highestVersion)
{ {
currentVersion mostModified = count;
= [[records objectAtIndex: count] objectForKey: @"c_version"]; highestVersion = version;
version = [currentVersion intValue];
if (version > highestVersion)
{
mostModified = count;
highestVersion = version;
}
} }
}
return mostModified; return mostModified;
} }
@@ -291,25 +289,25 @@
amount = 0; amount = 0;
if (!quickFields) if (!quickFields)
{ {
quickFields = [NSArray arrayWithObjects: @"c_givenname", @"c_cn", quickFields = [NSArray arrayWithObjects: @"c_givenname", @"c_cn",
@"c_sn", @"c_screenname", @"c_l", @"c_mail", @"c_sn", @"c_screenname", @"c_l", @"c_mail",
@"c_o", @"c_ou", @"c_telephonenumber", nil]; @"c_o", @"c_ou", @"c_telephonenumber", nil];
[quickFields retain]; [quickFields retain];
} }
max = [quickFields count]; max = [quickFields count];
for (count = 0; count < max; 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 length])
if ([value isKindOfClass: [NSString class]]) amount++;
{
if ([value length])
amount++;
}
else if ([value isKindOfClass: [NSNumber class]])
amount++;
} }
else if ([value isKindOfClass: [NSNumber class]])
amount++;
}
return amount; return amount;
} }
@@ -323,15 +321,14 @@
highestQFields = 0; highestQFields = 0;
for (count = 0; count < max; count++) for (count = 0; count < max; count++)
{
currentQFields = [self amountOfFilledQuickFields: [records objectAtIndex: count]];
if (currentQFields > highestQFields)
{ {
currentQFields mostQuickFields = count;
= [self amountOfFilledQuickFields: [records objectAtIndex: count]]; highestQFields = currentQFields;
if (currentQFields > highestQFields)
{
mostQuickFields = count;
highestQFields = currentQFields;
}
} }
}
return mostQuickFields; return mostQuickFields;
} }
@@ -399,10 +396,28 @@
} }
- (void) assignScores: (unsigned int *) scores - (void) assignScores: (unsigned int *) scores
toRecords: (NSArray *) records toRecords: (NSArray *) records
count: (unsigned int) max count: (unsigned int) max
withCardsInLists: (NSArray *) cardsInLists 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; int recordIndex;
recordIndex = [self mostModifiedRecord: records count: max]; recordIndex = [self mostModifiedRecord: records count: max];

View File

@@ -634,7 +634,7 @@
if (authname == nil || authpwd == nil) 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; return NO;
} }

View File

@@ -210,8 +210,7 @@
GCSFolder *folder; GCSFolder *folder;
BOOL rc; BOOL rc;
folderPath = [NSString stringWithFormat: @"/Users/%@/Calendar/%@", folderPath = [NSString stringWithFormat: @"/Users/%@/Calendar/%@", username, folderId];
username, folderId];
folder = [fom folderAtPath: folderPath]; folder = [fom folderAtPath: folderPath];
if (folder) if (folder)
rc = [self truncateEntriesFromFolder: folder usingDate: date]; rc = [self truncateEntriesFromFolder: folder usingDate: date];
@@ -238,12 +237,13 @@
// in the default timezone. // in the default timezone.
s = [NSString stringWithFormat: @"%@ GMT", date]; s = [NSString stringWithFormat: @"%@ GMT", date];
d = [NSCalendarDate dateWithString: s calendarFormat: @"%Y-%m-%dT%H:%M:%S %Z"]; d = [NSCalendarDate dateWithString: s calendarFormat: @"%Y-%m-%dT%H:%M:%S %Z"];
NSLog(@"Date is: %@", d);
fom = [GCSFolderManager defaultFolderManager]; fom = [GCSFolderManager defaultFolderManager];
if (d && fom) if (d && fom)
rc = [self processFolder: folder rc = [self processFolder: folder
ofUser: username ofUser: username
date: d date: d
withFoM: fom]; withFoM: fom];
else else
rc = NO; rc = NO;

View File

@@ -146,6 +146,9 @@
[helpString appendFormat: @"\t%-20@-- %@\n", [helpString appendFormat: @"\t%-20@-- %@\n",
command, [currentTool objectAtIndex: 1]]; 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); NSLog (@"%@", helpString);
} }