/*
Eteria IRC Client, an RFC 1459 compliant client program written in Java.
Copyright (C) 2000-2001 Javier Kohen <jkohen at tough.com>
This program 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 of the License, or
(at your option) any later version.
This program 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; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package ar.com.jkohen.irc;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.Observable;
public class Channel extends Observable
{
public static final int TOPIC_MASK = 0x01;
public static final int MODERATED_MASK = 0x02;
public static final int SECRET_MASK = 0x04;
public static final int INVITATION_MASK = 0x08;
public static final int REGISTERED_MASK = 0x10;
public static final int NONICK_MASK = 0x20;
private String tag;
private String topic;
private int limit = -1;
private String key = "";
private int modes_mask;
private Hashtable users;
public Channel(String tag)
{
this.tag = tag;
this.users = new Hashtable();
}
public String getTag()
{
return tag;
}
/* Method setTag makes no sense as a channel's tag can't be changed. */
public String getTopic()
{
return topic;
}
public void setTopic(String topic)
{
this.topic = topic;
setChanged();
notifyObservers("topic");
}
/*
* User related methods.
*/
public void add(String nick)
{
int mask = Modes.symbolicToMask(nick.charAt(0));
nick = Modes.canonicalizeNick(nick);
User user = new User(nick);
user.setModes(mask);
synchronized (users)
{
users.put(nick, user);
}
setChanged();
notifyObservers("add ".concat(nick));
}
public void remove(String nick)
{
synchronized (users)
{
User user = (User) users.remove(nick);
if (user == null)
return;
}
setChanged();
notifyObservers("remove ".concat(nick));
}
public void rename(String nick, String new_nick)
{
synchronized (users)
{
User user = (User) users.remove(nick);
if (user == null)
return;
user.setTag(new_nick);
users.put(new_nick, user);
}
setChanged();
notifyObservers("rename ".concat(nick).concat(" ").concat(new_nick));
}
public void clean()
{
synchronized (users)
{
users.clear();
}
update();
}
public void update()
{
setChanged();
notifyObservers("refresh");
}
public void update(String s)
{
if (contains(s))
{
setChanged();
notifyObservers("update ".concat(s));
}
}
public User get(String nick)
{
return (User) users.get(nick);
}
public boolean contains(String nick)
{
return users.containsKey(nick);
}
public int number()
{
return(users.size());
}
public User [] elements()
{
User [] a;
Enumeration e;
synchronized (users)
{
a = new User [users.size()];
e = users.elements();
}
for (int i = 0; e.hasMoreElements(); i++)
a[i] = (User) e.nextElement();
return a;
}
/*
* Mode related methods.
*/
public int getLimit()
{
return(limit);
}
public void setLimit(String l)
{
try
{
this.limit = Integer.parseInt(l);
} catch (NumberFormatException e) { this.limit = -1; }
}
public String getKey()
{
return(key);
}
public void setKey(boolean sign, String k)
{
if (sign)
this.key = k;
else
this.key = "";
}
/**
* Set channel, users or global modes.
*/
public void setModes()
{
setChanged();
notifyObservers("mode");
}
public void setModes(String modes, String [] params)
{
char [] mode_ary = modes.toCharArray();
boolean sign = false;
int j = 0;
for (int i = 0; i < mode_ary.length; i++)
{
switch (mode_ary[i])
{
case '+':
sign = true;
break;
case '-':
sign = false;
break;
/* Channel modes which handle additional parameters */
case 'k':
if (j < params.length)
setKey(sign, params[j++]);
break;
case 'l':
if (j < params.length)
setLimit(sign ? params[j++] : "");
break;
/* Channel modes without parameters */
case 't':
setChannelModes(sign, Channel.TOPIC_MASK);
break;
case 'm':
setChannelModes(sign, Channel.MODERATED_MASK);
break;
case 's':
setChannelModes(sign, Channel.SECRET_MASK);
break;
case 'i':
setChannelModes(sign, Channel.INVITATION_MASK);
break;
/* Non RFC1459 channel modes */
case 'r':
setChannelModes(sign, Channel.REGISTERED_MASK);
break;
case 'N':
setChannelModes(sign, Channel.NONICK_MASK);
break;
/* These modes aren't handled, but are known to carry a parameter which must be skipped. */
case 'b':
case 'e':
case 'I':
j++;
break;
/*
case 'v':
if (j < params.length)
setUserModes(params[j++], sign, User.VOICE_MASK);
break;
case 'h':
if (j < params.length)
setUserModes(params[j++], sign, User.HALFOP_MASK);
break;
case 'o':
if (j < params.length)
setUserModes(params[j++], sign, User.OP_MASK);
break;
case 'a':
if (j < params.length)
setUserModes(params[j++], sign, User.ADMIN_MASK);
break;
case 'q':
if (j < params.length)
setUserModes(params[j++], sign, User.OWNER_MASK);
break;
*/
/* Channel modes which set a prefix to a user */
default:
if (j < params.length)
{
if (setUserMode(mode_ary[i], params[j], sign))
j++;
}
}
}
}
/*
private void setUserModes(String nick, boolean sign, int mask)
{
User user = get(nick);
if(user == null)
return;
int cur_mask = user.getModes();
if (sign)
cur_mask |= mask;
else
cur_mask &= ~mask;
user.setModes(cur_mask);
setChanged();
notifyObservers("update ".concat(nick));
}
*/
private boolean setUserMode(char mode, String nick, boolean sign)
{
int mask = Modes.alphaToMask(mode);
if (mask == User.NORMAL_MASK)
return(false);
User user = get(nick);
if(user == null)
return(true);
int cur_mask = user.getModes();
if (sign)
cur_mask |= mask;
else
cur_mask &= ~mask;
user.setModes(cur_mask);
setChanged();
notifyObservers("update ".concat(nick));
return(true);
}
private void setChannelModes(boolean sign, int mask)
{
if (sign)
modes_mask |= mask;
else
modes_mask &= ~mask;
}
public boolean isTopicSettable()
{
return ((modes_mask & TOPIC_MASK) == 0);
}
public boolean isModerated()
{
return ((modes_mask & MODERATED_MASK) != 0);
}
public boolean isInvitOnly()
{
return ((modes_mask & INVITATION_MASK) != 0);
}
public boolean isSecret()
{
return ((modes_mask & SECRET_MASK) != 0);
}
public boolean isRegistered()
{
return ((modes_mask & REGISTERED_MASK) != 0);
}
public boolean canNick()
{
return ((modes_mask & NONICK_MASK) == 0);
}
public static boolean isChannel(String s)
{
if (s != null && !s.equals(""))
{
char ch = s.charAt(0);
return (ch == '&' || ch == '#' || ch == '+' || ch == '!');
}
return (false);
}
}