diff --git a/ChangeLog b/ChangeLog index 7d935bc7a..e37e82dbb 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,11 @@ +2012-04-04 Jean Raby + + * Added a new tool: 'sogo-tool expire-sessions' + Along with the associated new cronjob, this allows + user sessions expiration without a custom script. + + * While there, sort tools in sogo-tool output + 2012-04-03 Francis Lachapelle * Tools/SOGoToolRemoveDoubles.m (-removeDoublesFromFolder) diff --git a/Scripts/sogo.cron b/Scripts/sogo.cron index f92405c89..b9824d1e6 100644 --- a/Scripts/sogo.cron +++ b/Scripts/sogo.cron @@ -4,6 +4,11 @@ # Make sure to set authname and authpassword with the credentials of a sieve admin #0 0 * * * sogo /usr/sbin/sogo-tool expire-autoreply authname:authpassword +# Session cleanup - runs every minute +# - Ajust the nbMinutes parameter to suit your needs +# Example: Sessions without activity since 60 minutes will be dropped: +#* * * * * sogo /usr/sbin/sogo-tool expire-sessions 60 + # Email alarms - runs every minutes #* * * * * sogo /usr/sbin/sogo-ealarms-notify diff --git a/Tools/GNUmakefile b/Tools/GNUmakefile index 33417f935..99235cb8d 100644 --- a/Tools/GNUmakefile +++ b/Tools/GNUmakefile @@ -18,7 +18,8 @@ $(SOGO_TOOL)_OBJC_FILES += \ SOGoToolRemove.m \ SOGoToolRenameUser.m \ SOGoToolUserPreferences.m \ - SOGoToolExpireAutoReply.m + SOGoToolExpireAutoReply.m \ + SOGoToolExpireUserSessions.m TOOL_NAME += $(SOGO_TOOL) ### diff --git a/Tools/SOGoToolExpireUserSessions.m b/Tools/SOGoToolExpireUserSessions.m new file mode 100644 index 000000000..8eb530f3b --- /dev/null +++ b/Tools/SOGoToolExpireUserSessions.m @@ -0,0 +1,178 @@ +/* SOGoToolExpireUserSessions.m - this file is part of SOGo + * + * Copyright (C) 2012 Inverse inc. + * + * Author: Jean Raby + * + * 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 +#import + +#import + +#import +#import + +#import + +#import +#import +#import +#import + +#import "SOGoTool.h" + +@interface SOGoToolExpireUserSessions : SOGoTool +@end + +@implementation SOGoToolExpireUserSessions + ++ (void) initialize +{ +} + ++ (NSString *) command +{ + return @"expire-sessions"; +} + ++ (NSString *) description +{ + return @"Expires user sessions without activity for specified number of minutes"; +} + +- (void) usage +{ + fprintf (stderr, "expire-sessions [nbMinutes]\n\n" + " nbMinutes Number of minutes of inactivity after which a user session will be expired\n" + "\n" + "The SOGoSessionExpireMinutes user default will be used if nbMinutes is not specified\n" + "The expire-sessions action should be configured as a cronjob.\n"); +} + +- (BOOL) expireUserSessionOlderThan: (int) nbMinutes +{ + BOOL rc; + EOAdaptorChannel *channel; + GCSChannelManager *cm; + NSArray *attrs, *qValues; + NSDictionary *qresult; + NSException *ex; + NSString *sql, *sessionsFolderURL; + NSURL *tableURL; + NSUserDefaults *ud; + + unsigned int now, oldest; + int sessionsToDelete; + + rc=YES; + ud = [NSUserDefaults standardUserDefaults]; + now = [[NSCalendarDate calendarDate] timeIntervalSince1970]; + oldest = now - (nbMinutes * 60); + + sessionsFolderURL = [ud stringForKey: @"OCSSessionsFolderURL"]; + if (!sessionsFolderURL) + { + if (verbose) + NSLog(@"Couldn't read OCSSessionsFolderURL"); + return rc = NO; + } + + tableURL = [[NSURL alloc] initWithString: sessionsFolderURL]; + cm = [GCSChannelManager defaultChannelManager]; + channel = [cm acquireOpenChannelForURL: tableURL]; + if (!channel) + { + /* FIXME: nice error msg */ + NSLog(@"Can't aquire channel"); + return rc=NO; + } + + sql = [NSString stringWithFormat: @"SELECT count(*) FROM %@ WHERE c_lastseen <= %d;", + [tableURL gcsTableName], oldest]; + ex = [channel evaluateExpressionX: sql]; + if (ex) + { + NSLog(@"%@", [ex reason]); + [ex raise]; + return rc=NO; + } + + attrs = [channel describeResults: NO]; + /* only one row */ + qresult = [channel fetchAttributes: attrs withZone: NULL]; + qValues = [qresult allValues]; + sessionsToDelete = [[qValues objectAtIndex: 0] intValue]; + if (sessionsToDelete) + { + if (verbose) + NSLog(@"Will be removing %d sessions", sessionsToDelete); + [channel cancelFetch]; + sql = [NSString stringWithFormat: @"DELETE FROM %@ WHERE c_lastseen <= %d;", + [tableURL gcsTableName], oldest]; + if (verbose) + NSLog(@"Removing sessions older than %d minute(s)", nbMinutes); + ex = [channel evaluateExpressionX: sql]; + if (ex) + { + NSLog(@"An exception occured while deleting old sessions: %@", [ex reason]); + [ex raise]; + return rc=NO; + } + } + else + { + if (verbose) + NSLog(@"No session to remove", sessionsToDelete); + } + + [cm releaseChannel: channel]; + return rc; +} + +- (BOOL) run +{ + BOOL rc; + int sessionExpireMinutes=0; + + rc = NO; + + if ([arguments count]) + { + sessionExpireMinutes = [[arguments objectAtIndex: 0] intValue]; + } + + if (sessionExpireMinutes > 0) + { + rc = [self expireUserSessionOlderThan: sessionExpireMinutes]; + } + else + { + [self usage]; + } + + return rc; +} + +@end diff --git a/Tools/sogo-tool.m b/Tools/sogo-tool.m index fc93456e9..ca7f052c0 100644 --- a/Tools/sogo-tool.m +++ b/Tools/sogo-tool.m @@ -143,11 +143,11 @@ [helpString appendString: @" argument1, ...\targuments passed to the" @" specified command\n\n"]; [helpString appendString: @" Available commands:\n"]; - toolsEnum = [[tools allKeys] objectEnumerator]; + toolsEnum = [[[tools allKeys] sortedArrayUsingSelector:@selector(caseInsensitiveCompare:)] objectEnumerator]; while ((command = [toolsEnum nextObject])) { currentTool = [tools objectForKey: command]; - [helpString appendFormat: @"\t%@\t-- %@\n", + [helpString appendFormat: @"\t%-20@-- %@\n", command, [currentTool objectAtIndex: 1]]; }