|
@@ -26,6 +26,7 @@ import com.dmdirc.parser.common.ParserError;
|
26
|
26
|
import com.dmdirc.parser.common.QueuePriority;
|
27
|
27
|
import com.dmdirc.parser.events.ChannelJoinEvent;
|
28
|
28
|
import com.dmdirc.parser.events.ChannelSelfJoinEvent;
|
|
29
|
+import com.dmdirc.parser.events.DataOutEvent;
|
29
|
30
|
import com.dmdirc.parser.interfaces.ChannelClientInfo;
|
30
|
31
|
import com.dmdirc.parser.interfaces.ChannelInfo;
|
31
|
32
|
import com.dmdirc.parser.irc.CapabilityState;
|
|
@@ -36,9 +37,14 @@ import com.dmdirc.parser.irc.IRCParser;
|
36
|
37
|
import com.dmdirc.parser.irc.ModeManager;
|
37
|
38
|
import com.dmdirc.parser.irc.PrefixModeManager;
|
38
|
39
|
import com.dmdirc.parser.irc.ProcessorNotFoundException;
|
|
40
|
+import com.dmdirc.parser.irc.events.IRCDataOutEvent;
|
|
41
|
+import net.engio.mbassy.listener.Handler;
|
|
42
|
+import net.engio.mbassy.listener.Invoke;
|
39
|
43
|
|
40
|
44
|
import java.time.LocalDateTime;
|
41
|
45
|
import java.util.Arrays;
|
|
46
|
+import java.util.LinkedList;
|
|
47
|
+import java.util.Queue;
|
42
|
48
|
|
43
|
49
|
import javax.inject.Inject;
|
44
|
50
|
import javax.inject.Named;
|
|
@@ -54,6 +60,10 @@ public class ProcessJoin extends IRCProcessor {
|
54
|
60
|
private final ModeManager userModeManager;
|
55
|
61
|
/** Mode manager to use for channel modes. */
|
56
|
62
|
private final ModeManager chanModeManager;
|
|
63
|
+ /** Pending Joins. */
|
|
64
|
+ private final Queue<String> pendingJoins = new LinkedList<>();
|
|
65
|
+ /** Pending Join Keys. */
|
|
66
|
+ private final Queue<String> pendingJoinKeys = new LinkedList<>();
|
57
|
67
|
|
58
|
68
|
/**
|
59
|
69
|
* Create a new instance of the IRCProcessor Object.
|
|
@@ -71,6 +81,8 @@ public class ProcessJoin extends IRCProcessor {
|
71
|
81
|
this.prefixModeManager = prefixModeManager;
|
72
|
82
|
this.userModeManager = userModeManager;
|
73
|
83
|
this.chanModeManager = chanModeManager;
|
|
84
|
+
|
|
85
|
+ getCallbackManager().subscribe(this);
|
74
|
86
|
}
|
75
|
87
|
|
76
|
88
|
/**
|
|
@@ -171,22 +183,58 @@ public class ProcessJoin extends IRCProcessor {
|
171
|
183
|
parser.addChannel(iChannel);
|
172
|
184
|
sendString("MODE " + iChannel.getName(), QueuePriority.LOW);
|
173
|
185
|
|
174
|
|
- final String pendingJoin = parser.getPendingJoins().poll();
|
175
|
|
- final String pendingJoinKey = parser.getPendingJoinKeys().poll();
|
176
|
|
- if (pendingJoin.equalsIgnoreCase(channelName)) {
|
|
186
|
+ final String pendingJoin = pendingJoins.poll();
|
|
187
|
+ final String pendingJoinKey = pendingJoinKeys.poll();
|
|
188
|
+ if (pendingJoin != null && pendingJoin.equalsIgnoreCase(channelName)) {
|
177
|
189
|
callDebugInfo(IRCParser.DEBUG_INFO, "processJoin: Guessing channel Key: " + pendingJoin + " -> " + pendingJoinKey);
|
178
|
190
|
iChannel.setInternalPassword(pendingJoinKey == null ? "" : pendingJoinKey);
|
179
|
191
|
} else {
|
180
|
|
- // Out of sync, clear.
|
181
|
|
- parser.getPendingJoins().clear();
|
182
|
|
- parser.getPendingJoinKeys().clear();
|
|
192
|
+ // Out of sync, clear
|
|
193
|
+ callDebugInfo(IRCParser.DEBUG_INFO, "processJoin: pending join keys out of sync (Got: " + pendingJoin + ", Wanted: " + channelName + ") - Clearing.");
|
|
194
|
+ pendingJoins.clear();
|
|
195
|
+ pendingJoinKeys.clear();
|
183
|
196
|
}
|
184
|
197
|
|
185
|
198
|
callChannelSelfJoin(iChannel);
|
186
|
199
|
} else {
|
187
|
200
|
// Some kind of failed to join, pop the pending join queues.
|
188
|
|
- parser.getPendingJoins().poll();
|
189
|
|
- parser.getPendingJoinKeys().poll();
|
|
201
|
+ final String pendingJoin = pendingJoins.poll();
|
|
202
|
+ final String pendingJoinKey = pendingJoinKeys.poll();
|
|
203
|
+ callDebugInfo(IRCParser.DEBUG_INFO, "processJoin: Failed to join channel (" + sParam + ") - Skipping " + pendingJoin + " (" + pendingJoinKey + ")");
|
|
204
|
+ }
|
|
205
|
+ }
|
|
206
|
+
|
|
207
|
+ @Handler(delivery = Invoke.Synchronously, condition = "msg.action == 'JOIN'")
|
|
208
|
+ public void handleDataOut(final IRCDataOutEvent event) {
|
|
209
|
+ // As long as this is called before the resulting DataIn
|
|
210
|
+ // Processors fire then this will work, otherwise we'll end
|
|
211
|
+ // up with an out-of-sync pendingJoins list.
|
|
212
|
+
|
|
213
|
+ final String[] newLine = event.getTokenisedData();
|
|
214
|
+ if (newLine.length > 1) {
|
|
215
|
+ final Queue<String> keys = new LinkedList<>();
|
|
216
|
+
|
|
217
|
+ if (newLine.length > 2) {
|
|
218
|
+ keys.addAll(Arrays.asList(newLine[2].split(",")));
|
|
219
|
+ }
|
|
220
|
+
|
|
221
|
+ // PendingJoins and PendingJoinKeys should always be the same length (even if no key was given).
|
|
222
|
+ //
|
|
223
|
+ // We don't get any errors for channels we try to join that we are already in
|
|
224
|
+ // But the IRCD will still swallow the key attempt.
|
|
225
|
+ //
|
|
226
|
+ // Make sure that we always have a guessed key for every channel (even if null) and that we
|
|
227
|
+ // don't have guesses for channels we are already in.
|
|
228
|
+ for (final String chan : newLine[1].split(",")) {
|
|
229
|
+ final String key = keys.poll();
|
|
230
|
+ if (getChannel(chan) == null) {
|
|
231
|
+ callDebugInfo(IRCParser.DEBUG_INFO, "processJoin: Intercepted possible channel Key: " + chan + " -> " + key);
|
|
232
|
+ pendingJoins.add(chan);
|
|
233
|
+ pendingJoinKeys.add(key);
|
|
234
|
+ } else {
|
|
235
|
+ callDebugInfo(IRCParser.DEBUG_INFO, "processJoin: Ignoring possible channel Key for existing channel: " + chan + " -> " + key);
|
|
236
|
+ }
|
|
237
|
+ }
|
190
|
238
|
}
|
191
|
239
|
}
|
192
|
240
|
|