/* This file is part of leafdigital leafChat. leafChat 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 3 of the License, or (at your option) any later version. leafChat 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 leafChat. If not, see <http://www.gnu.org/licenses/>. Copyright 2011 Samuel Marshall. */ package com.leafdigital.idle; import java.awt.Point; import java.util.*; import util.*; import com.leafdigital.idle.api.Idle; import com.leafdigital.irc.api.*; import com.leafdigital.prefs.api.*; import com.leafdigital.prefsui.api.PreferencesUI; import leafchat.core.api.*; /** Plugin for handling auto-away/idle detection. */ public class IdlePlugin implements Plugin,Idle,Runnable { /** Preference to enable auto-away */ public final static String PREF_AUTOAWAY="auto-away"; /** Default auto-away (on) */ public final static String PREFDEFAULT_AUTOAWAY="t"; /** Preference to control idle timeout */ public final static String PREF_IDLETIME="idle-time"; /** Default idle timeout (15m) */ public final static String PREFDEFAULT_IDLETIME="15"; /** Preference to control what counts as activity */ public final static String PREF_ACTIVE="active"; /** Active value: IRC command */ public final static String PREFVALUE_ACTIVE_COMMAND="command"; /** Active value: mouse movement */ public final static String PREFVALUE_ACTIVE_MOUSE="mouse"; /** Default activity: mouse */ public final static String PREFDEFAULT_ACTIVE=PREFVALUE_ACTIVE_MOUSE; /** Preference to enable auto-unaway when command is typed */ public final static String PREF_AUTOUNAWAY="auto-unaway"; /** Default auto un-away (on) */ public final static String PREFDEFAULT_AUTOUNAWAY="t"; private final static long IDLECHECK_INTERVAL=30000; private int eventID; private long lastAction; private LinkedList<Server> markedServers=null; private PluginContext context; @Override public synchronized void init(PluginContext context, PluginLoadReporter reporter) throws GeneralException { this.context=context; // Become a singleton context.registerSingleton(Idle.class,this); // Register prefs page PreferencesUI preferencesUI=context.getSingle(PreferencesUI.class); preferencesUI.registerPage(this,(new IdlePage(context)).getPage()); // Start tracking idle state eventID=TimeUtils.addTimedEvent(this,IDLECHECK_INTERVAL,true); } @Override public synchronized void close() throws GeneralException { TimeUtils.cancelTimedEvent(eventID); } private Point getMousePosition() { try { Object pointerInfo=Class.forName("java.awt.MouseInfo"). getMethod("getPointerInfo").invoke(null); return (Point)pointerInfo.getClass(). getMethod("getLocation").invoke(pointerInfo); } catch(Exception e) { return new Point(0,0); } } private Point lastMousePosition=null; /** Executed every 30 seconds to check if the user has idled too long */ @Override public synchronized void run() { try { long now=System.currentTimeMillis(); if(lastAction==0) lastAction=now; Preferences p=context.getSingle(Preferences.class); PreferencesGroup pg=p.getGroup(context.getPlugin()); boolean includeMouse=pg.get(IdlePlugin.PREF_ACTIVE,IdlePlugin.PREFDEFAULT_ACTIVE).equals( IdlePlugin.PREFVALUE_ACTIVE_MOUSE) && PlatformUtils.isJavaVersionAtLeast(1,5); if(includeMouse) { Point mousePosition=getMousePosition(); if(lastMousePosition==null || !lastMousePosition.equals(mousePosition)) { lastAction=now; lastMousePosition=mousePosition; } } boolean enabled=p.toBoolean( pg.get(IdlePlugin.PREF_AUTOAWAY,IdlePlugin.PREFDEFAULT_AUTOAWAY)); if(enabled) { int minutes=p.toInt( pg.get(IdlePlugin.PREF_IDLETIME,IdlePlugin.PREFDEFAULT_IDLETIME)); if( now-lastAction > minutes*60000L ) setAutoAway(minutes); } } finally { eventID=TimeUtils.addTimedEvent(this,IDLECHECK_INTERVAL,true); } } @Override public String toString() { // Used to display in system log etc. return "Idle plugin"; } private void setAutoAway(int minutes) { String message="Auto-away: idle "+minutes+" minutes"; Connections c=context.getSingle(Connections.class); Server[] servers=c.getConnected(); markedServers = new LinkedList<Server>(); for(int i=0;i<servers.length;i++) { // Mark away if the user hasn't done it manually if(!servers[i].isAway()) { markedServers.add(servers[i]); servers[i].sendLine(IRCMsg.constructBytes("AWAY :"+message)); } } } private void cancelAutoAway() { // Mark unaway for all servers that we marked away if(markedServers!=null) { for(Iterator<Server> i=markedServers.iterator();i.hasNext();) { Server s = i.next(); if(s.isConnected() && s.isAway()) { s.sendLine(IRCMsg.constructBytes("AWAY")); } } } markedServers=null; } @Override public synchronized void userAwake(String action) { lastAction=System.currentTimeMillis(); if(markedServers!=null) { // If they just canceled away, we never count that as a reason to cancel // away ourselves. if(!action.equals(Idle.AWAKE_UNAWAY)) { Preferences p=context.getSingle(Preferences.class); PreferencesGroup pg=p.getGroup(context.getPlugin()); boolean cancel=p.toBoolean( pg.get(IdlePlugin.PREF_AUTOUNAWAY,IdlePlugin.PREFDEFAULT_AUTOUNAWAY)); if(cancel) { cancelAutoAway(); } } markedServers=null; } } }