Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

API for bans, abstracted to support quiets/exempt #122

Merged
merged 1 commit into from
Aug 9, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 24 additions & 0 deletions src/main/java/org/kitteh/irc/client/library/element/Channel.java
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,9 @@
import org.kitteh.irc.client.library.command.TopicCommand;
import org.kitteh.irc.client.library.element.mode.ChannelMode;
import org.kitteh.irc.client.library.element.mode.ChannelUserMode;
import org.kitteh.irc.client.library.element.mode.ModeInfo;
import org.kitteh.irc.client.library.element.mode.ModeStatusList;
import org.kitteh.irc.client.library.event.channel.ChannelModeInfoListEvent;
import org.kitteh.irc.client.library.event.channel.ChannelUsersUpdatedEvent;
import org.kitteh.irc.client.library.util.Sanity;

Expand Down Expand Up @@ -83,6 +85,16 @@ default Optional<Channel> getLatest() {
return this.getClient().getChannel(this.getName());
}

/**
* Gets the tracked mode info for the channel, if tracked.
*
* @param mode type A mode to acquire
* @return list of mode info if tracked, empty if not tracked
* @throws IllegalArgumentException for null or non-type-A mode
*/
@Nonnull
Optional<List<ModeInfo>> getModeInfoList(@Nonnull ChannelMode mode);

/**
* Gets the channel's current known modes.
*
Expand Down Expand Up @@ -241,6 +253,18 @@ default void part(@Nonnull String reason) {
this.getClient().removeChannel(this.getName(), reason);
}

/**
* Sets whether a particular type A mode should be tracked for this
* channel, and sends a request for the full list.
*
* @param mode mode to track
* @param track true to track, false to stop tracking
* @throws IllegalArgumentException for null or non-type-A mode
* @throws IllegalStateException if not in channel
* @see ChannelModeInfoListEvent
*/
void setModeInfoTracking(@Nonnull ChannelMode mode, boolean track);

/**
* Attempts to set the topic of the channel.
*
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
/*
* * Copyright (C) 2013-2016 Matt Baxter http://kitteh.org
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use, copy,
* modify, merge, publish, distribute, sublicense, and/or sell copies
* of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package org.kitteh.irc.client.library.element.mode;

import org.kitteh.irc.client.library.Client;
import org.kitteh.irc.client.library.command.ChannelModeCommand;
import org.kitteh.irc.client.library.element.Channel;
import org.kitteh.irc.client.library.util.Mask;

import javax.annotation.Nonnull;
import java.time.Instant;
import java.util.Optional;

/**
* Represents a type A mode information entry.
*/
public interface ModeInfo {
/**
* Gets the name of the party listed as creating the entry. This may be a
* nickname, a service name, a server name, etc.
*
* @return name, if known, of who created this entry
*/
@Nonnull
Optional<String> getCreator();

/**
* Gets the channel for which this entry exists.
*
* @return the channel
*/
@Nonnull
Channel getChannel();

/**
* Gets the client that received this information.
*
* @return the client
*/
@Nonnull
Client getClient();

/**
* Gets the mask.
*
* @return the mask
*/
@Nonnull
Mask getMask();

/**
* Gets the mode for which this info exists.
*
* @return the mode
*/
@Nonnull
ChannelMode getMode();

/**
* Gets the time at which this entry was created.
*
* @return creation time, if known
*/
@Nonnull
Optional<Instant> getCreationTime();

/**
* Attempts to remove this item from the channel.
*/
default void remove() {
new ChannelModeCommand(this.getClient(), this.getChannel().getName()).add(false, this.getMode(), this.getMask().asString()).execute();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
/*
* * Copyright (C) 2013-2016 Matt Baxter http://kitteh.org
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use, copy,
* modify, merge, publish, distribute, sublicense, and/or sell copies
* of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package org.kitteh.irc.client.library.event.channel;

import org.kitteh.irc.client.library.Client;
import org.kitteh.irc.client.library.element.Channel;
import org.kitteh.irc.client.library.element.ServerMessage;
import org.kitteh.irc.client.library.element.mode.ChannelMode;
import org.kitteh.irc.client.library.element.mode.ModeInfo;
import org.kitteh.irc.client.library.event.abstractbase.ChannelEventBase;

import javax.annotation.Nonnull;
import java.util.Collections;
import java.util.List;

/**
* A list of mode info is available!
*/
public class ChannelModeInfoListEvent extends ChannelEventBase {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I assume this is for bans, quiets, etc.
There's currently no way, that I can see, to determine which type of list this is.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

From latest commit - "Needs way of knowing it's a ban"

private final ChannelMode mode;
private final List<ModeInfo> info;

/**
* Constructs the event.
*
* @param client client for which this is occurring
* @param originalMessages original messages
* @param channel channel with this info
* @param mode mode for which the info exists
* @param info list of info
*/
public ChannelModeInfoListEvent(@Nonnull Client client, @Nonnull List<ServerMessage> originalMessages, @Nonnull Channel channel, @Nonnull ChannelMode mode, @Nonnull List<ModeInfo> info) {
super(client, originalMessages, channel);
this.mode = mode;
this.info = Collections.unmodifiableList(info);
}

/**
* Gets the mode info's mode.
*
* @return mode
*/
@Nonnull
public ChannelMode getMode() {
return this.mode;
}

/**
* Gets the channel's mode info.
*
* @return info
*/
@Nonnull
public List<ModeInfo> getModeInfo() {
return this.info;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@


import org.kitteh.irc.client.library.Client;
import org.kitteh.irc.client.library.command.ChannelModeCommand;
import org.kitteh.irc.client.library.element.Actor;
import org.kitteh.irc.client.library.element.Channel;
import org.kitteh.irc.client.library.element.ISupportParameter;
Expand All @@ -33,6 +34,7 @@
import org.kitteh.irc.client.library.element.User;
import org.kitteh.irc.client.library.element.mode.ChannelMode;
import org.kitteh.irc.client.library.element.mode.ChannelUserMode;
import org.kitteh.irc.client.library.element.mode.ModeInfo;
import org.kitteh.irc.client.library.element.mode.ModeStatus;
import org.kitteh.irc.client.library.element.mode.ModeStatusList;
import org.kitteh.irc.client.library.util.CIKeyMap;
Expand All @@ -48,6 +50,7 @@
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Objects;
Expand Down Expand Up @@ -156,6 +159,8 @@ synchronized T snapshot(@Nonnull Supplier<T> supplier) {

class IRCChannel extends IRCStaleable<IRCChannelSnapshot> {
private final Map<Character, ModeStatus<ChannelMode>> channelModes = new HashMap<>();
private final Map<Character, List<ModeInfo>> modeInfoLists = new HashMap<>();
private final Set<Character> trackedModes = new HashSet<>();
private final Map<String, Set<ChannelUserMode>> modes;
private volatile boolean fullListReceived;
private long lastWho = System.currentTimeMillis();
Expand Down Expand Up @@ -209,6 +214,35 @@ IRCChannelSnapshot snapshot() {
return super.snapshot(() -> new IRCChannelSnapshot(IRCChannel.this, new IRCChannelTopicSnapshot(IRCChannel.this.topicTime, IRCChannel.this.topic, IRCChannel.this.topicSetter)));
}

void trackMode(@Nonnull ChannelMode mode, boolean track) {
if (track && this.trackedModes.add(mode.getChar())) {
new ChannelModeCommand(ActorProvider.this.client, this.getName()).add(true, mode).execute();
} else if (!track) {
this.trackedModes.remove(mode.getChar());
}
}

void setModeInfoList(char character, @Nonnull List<ModeInfo> modeInfoList) {
if (this.trackedModes.contains(character)) {
this.modeInfoLists.put(character, modeInfoList);
}
this.markStale();
}

void trackModeInfo(boolean add, @Nonnull ModeInfo modeInfo) {
if (add) {
this.modeInfoLists.get(modeInfo.getMode().getChar()).add(modeInfo);
} else {
Iterator<ModeInfo> iterator = this.modeInfoLists.get(modeInfo.getMode().getChar()).iterator();
while (iterator.hasNext()) {
if (modeInfo.getMask().equals(iterator.next().getMask())) {
iterator.remove();
return;
}
}
}
}

void trackUser(@Nonnull IRCUser user, @Nonnull Set<ChannelUserMode> modes) {
ActorProvider.this.trackUser(user);
this.setModes(user.getNick(), modes);
Expand Down Expand Up @@ -276,6 +310,13 @@ private void setModes(@Nonnull String nick, @Nonnull Set<ChannelUserMode> modes)
}

void updateChannelModes(ModeStatusList<ChannelMode> statusList) {
statusList.getStatuses().stream().filter(status -> (status.getMode() instanceof ChannelUserMode) && (status.getParameter().isPresent())).forEach(status -> {
if (status.isSetting()) {
this.trackUserModeAdd(status.getParameter().get(), (ChannelUserMode) status.getMode());
} else {
this.trackUserModeRemove(status.getParameter().get(), (ChannelUserMode) status.getMode());
}
});
statusList.getStatuses().stream().filter(status -> !(status.getMode() instanceof ChannelUserMode) && (status.getMode().getType() != ChannelMode.Type.A_MASK)).forEach(status -> {
if (status.isSetting()) {
this.channelModes.put(status.getMode().getChar(), status);
Expand Down Expand Up @@ -331,6 +372,7 @@ public String toString() {

class IRCChannelSnapshot extends IRCActorSnapshot implements Channel {
private final ModeStatusList<ChannelMode> channelModes;
private final Map<Character, List<ModeInfo>> modeInfoLists;
private final Map<String, SortedSet<ChannelUserMode>> modes;
private final List<String> names;
private final Map<String, User> nickMap;
Expand All @@ -343,6 +385,11 @@ private IRCChannelSnapshot(@Nonnull IRCChannel channel, @Nonnull Topic topic) {
this.complete = channel.fullListReceived;
this.channelModes = ModeStatusList.of(channel.channelModes.values());
this.topic = topic;
this.modeInfoLists = new HashMap<>();
for (Map.Entry<Character, List<ModeInfo>> entry : channel.modeInfoLists.entrySet()) {
this.modeInfoLists.put(entry.getKey(), Collections.unmodifiableList(new ArrayList<>(entry.getValue())));
}
channel.trackedModes.stream().filter(character -> !this.modeInfoLists.containsKey(character)).forEach(character -> this.modeInfoLists.put(character, Collections.unmodifiableList(new ArrayList<>())));
Map<String, SortedSet<ChannelUserMode>> newModes = new CIKeyMap<>(ActorProvider.this.client);
Optional<ISupportParameter.Prefix> prefix = ActorProvider.this.client.getServerInfo().getISupportParameter("PREFIX", ISupportParameter.Prefix.class);
Comparator<ChannelUserMode> comparator = prefix.isPresent() ? Comparator.comparingInt(prefix.get().getModes()::indexOf) : null;
Expand All @@ -369,6 +416,14 @@ public String getMessagingName() {
return this.getName();
}

@Nonnull
@Override
public Optional<List<ModeInfo>> getModeInfoList(@Nonnull ChannelMode mode) {
Sanity.nullCheck(mode, "Mode cannot be null");
Sanity.truthiness(mode.getType() == ChannelMode.Type.A_MASK, "Mode type must be A, found " + mode.getType());
return Optional.ofNullable(this.modeInfoLists.get(mode.getChar()));
}

@Override
@Nonnull
public ModeStatusList<ChannelMode> getModes() {
Expand Down Expand Up @@ -412,6 +467,17 @@ public boolean hasCompleteUserData() {
return this.complete;
}

@Override
public void setModeInfoTracking(@Nonnull ChannelMode mode, boolean track) {
Sanity.nullCheck(mode, "Mode cannot be null");
Sanity.truthiness(mode.getType() == ChannelMode.Type.A_MASK, "Mode type must be A, found " + mode.getType());
IRCChannel channel = ActorProvider.this.getTrackedChannel(this.getName());
if (channel == null) {
throw new IllegalStateException("Not currently in channel " + this.getName());
}
channel.trackMode(mode, track);
}

@Override
public int hashCode() {
// RFC 2812 section 1.3 'Channel names are case insensitive.'
Expand Down
Loading