Browse Source

Add support for "CAP" extension.

(See: http://www.leeh.co.uk/draft-mitchell-irc-capabilities-02.html)

Change-Id: I9aaf2877770f86a93c9f8c525bea6315a7a8802b
Reviewed-on: http://gerrit.dmdirc.com/2541
Reviewed-by: Greg Holmes <greg@dmdirc.com>
Automatic-Compile: DMDirc Build Manager
tags/0.7rc1
Shane Mc Cormack 11 years ago
parent
commit
cb1c1ad110

+ 9
- 7
src/com/dmdirc/parser/irc/IRCParser.java View File

@@ -194,9 +194,7 @@ public class IRCParser extends BaseParser implements SecureParser, EncodingParse
194 194
     private IRCClientInfo myself = new IRCClientInfo(this, "myself").setFake(true);
195 195
     /** Hashtable storing all information gathered from 005. */
196 196
     final Map<String, String> h005Info = new HashMap<String, String>();
197
-    /** Does this server support timestamped IRC? */
198
-    boolean timestampedIRC = false;
199
-    /** difference in ms between our time and the servers time. */
197
+    /** difference in ms between our time and the servers time (used for timestampedIRC). */
200 198
     long tsdiff;
201 199
     /** Reference to the Processing Manager. */
202 200
     private final ProcessingManager myProcessingManager = new ProcessingManager(this);
@@ -923,6 +921,7 @@ public class IRCParser extends BaseParser implements SecureParser, EncodingParse
923 921
      * Send server connection strings (NICK/USER/PASS).
924 922
      */
925 923
     protected void sendConnectionStrings() {
924
+        sendString("CAP LS");
926 925
         if (getURI().getUserInfo() != null && !getURI().getUserInfo().isEmpty()) {
927 926
             sendString("PASS " + getURI().getUserInfo());
928 927
         }
@@ -1233,7 +1232,7 @@ public class IRCParser extends BaseParser implements SecureParser, EncodingParse
1233 1232
         callDataIn(line.getLine());
1234 1233
         String[] token = line.getTokens();
1235 1234
         Date lineTS = new Date();
1236
-        if (!token[0].isEmpty() && timestampedIRC && token[0].charAt(0) == '@') {
1235
+        if (!token[0].isEmpty() && token[0].charAt(0) == '@') {
1237 1236
             try {
1238 1237
                 final int tsEnd = token[0].indexOf('@', 1);
1239 1238
                 final long ts = Long.parseLong(token[0].substring(1, tsEnd));
@@ -1265,14 +1264,12 @@ public class IRCParser extends BaseParser implements SecureParser, EncodingParse
1265 1264
                     errorMessage.append(token[i]);
1266 1265
                 }
1267 1266
                 callServerError(errorMessage.toString());
1268
-            } else if (timestampedIRC && token[1].equalsIgnoreCase("TSIRC") && token.length > 3) {
1267
+            } else if (token[1].equalsIgnoreCase("TSIRC") && token.length > 3) {
1269 1268
                 if (token[2].equals("1")) {
1270 1269
                     try {
1271 1270
                         final long ts = Long.parseLong(token[3]);
1272 1271
                         tsdiff = ts - System.currentTimeMillis();
1273 1272
                     } catch (final NumberFormatException nfe) { /* Do nothing. */ }
1274
-                } else {
1275
-                    timestampedIRC = false;
1276 1273
                 }
1277 1274
             } else {
1278 1275
                 if (got001) {
@@ -1345,6 +1342,11 @@ public class IRCParser extends BaseParser implements SecureParser, EncodingParse
1345 1342
                                 break;
1346 1343
                             }
1347 1344
 
1345
+                            // CAP also happens here, so try that.
1346
+                            if (token[1].equalsIgnoreCase("CAP")) {
1347
+                                myProcessingManager.process(lineTS, sParam, token);
1348
+                            }
1349
+
1348 1350
                             // Otherwise, send to Notice Auth
1349 1351
                             try {
1350 1352
                                 myProcessingManager.process(lineTS, "Notice Auth", token);

+ 3
- 1
src/com/dmdirc/parser/irc/Process004005.java View File

@@ -150,9 +150,11 @@ public class Process004005 extends IRCProcessor {
150 150
                     } catch (ProcessorNotFoundException e) {
151 151
                     }
152 152
                 } else if ("TIMESTAMPEDIRC".equals(key)) {
153
-                    parser.timestampedIRC = true;
154 153
                     // Let the server know we also understand timestamped irc.
155 154
                     // See my other proposal: http://shanemcc.co.uk/irc/#timestamping
155
+                    // This might not be needed if the server advertises it via
156
+                    // CAP, but send it anyway as we don't currently keep state
157
+                    // with CAP.
156 158
                     parser.sendString("TIMESTAMPEDIRC ON", QueuePriority.HIGH);
157 159
                 }
158 160
             }

+ 97
- 0
src/com/dmdirc/parser/irc/ProcessCap.java View File

@@ -0,0 +1,97 @@
1
+/*
2
+ * Copyright (c) 2006-2012 DMDirc Developers
3
+ *
4
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
5
+ * of this software and associated documentation files (the "Software"), to deal
6
+ * in the Software without restriction, including without limitation the rights
7
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8
+ * copies of the Software, and to permit persons to whom the Software is
9
+ * furnished to do so, subject to the following conditions:
10
+ *
11
+ * The above copyright notice and this permission notice shall be included in
12
+ * all copies or substantial portions of the Software.
13
+ *
14
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20
+ * SOFTWARE.
21
+ */
22
+
23
+package com.dmdirc.parser.irc;
24
+
25
+import java.util.Date;
26
+
27
+/**
28
+ * Process CAP extension.
29
+ * There are currently no callbacks related to this, as it is just to tell
30
+ * the server what we support.
31
+ *
32
+ * For all the capabilities we support, we are always able to handle lines#
33
+ * either with or without the capability enabled, so we don't actually need to
34
+ * keep much/any state here, which makes this easy.
35
+ *
36
+ * See: http://www.leeh.co.uk/draft-mitchell-irc-capabilities-02.html
37
+ */
38
+public class ProcessCap extends TimestampedIRCProcessor {
39
+    /** Have we handled the pre-connect cap request? */
40
+    private boolean hasCapped = false;
41
+
42
+    /**
43
+     * Create a new instance of the IRCProcessor Object.
44
+     *
45
+     * @param parser IRCParser That owns this IRCProcessor
46
+     * @param manager ProcessingManager that is in charge of this IRCProcessor
47
+     */
48
+    protected ProcessCap(final IRCParser parser, final ProcessingManager manager) {
49
+        super(parser, manager);
50
+    }
51
+
52
+    /**
53
+     * Process CAP responses.
54
+     *
55
+     * @param sParam Type of line to process ("CAP")
56
+     * @param token IRCTokenised line to process
57
+     */
58
+    @Override
59
+    public void process(final Date date, final String sParam, final String[] token) {
60
+        // We will only automatically handle the first ever pre-001 CAP LS
61
+        // response.
62
+        // After that, the user may be sending stuff themselves so we do
63
+        // nothing.
64
+        if (!hasCapped && !parser.got001 && token.length > 4 && token[3].equalsIgnoreCase("LS")) {
65
+            final String[] caps = token[token.length - 1].split(" ");
66
+            for (final String cap : caps) {
67
+                if (cap.equalsIgnoreCase("multi-prefix") || cap.equalsIgnoreCase("tsirc") || cap.equalsIgnoreCase("userhost-in-names")) {
68
+                    // Send cap requests as individual lines, as some servers
69
+                    // only appear to accept them one at a time.
70
+                    parser.sendRawMessage("CAP REQ :" + cap);
71
+                }
72
+            }
73
+
74
+            // If this is the last of the LS responses, set hasCapped to true
75
+            // so that we don't try this again, and send "CAP END"
76
+            // We will accept any of the following to be the end of the list:
77
+            //     :DFBnc.Server CAP Dataforce LS :some caps
78
+            //     :DFBnc.Server CAP Dataforce LS
79
+            // but not:
80
+            //     :DFBnc.Server CAP Dataforce LS *
81
+            if (token.length == 4 || (token.length == 5 && !token[4].equals("*"))) {
82
+                hasCapped = true;
83
+                parser.sendRawMessage("CAP END");
84
+            }
85
+        }
86
+    }
87
+
88
+    /**
89
+     * What does this IRCProcessor handle.
90
+     *
91
+     * @return String[] with the names of the tokens we handle.
92
+     */
93
+    @Override
94
+    public String[] handles() {
95
+        return new String[]{"CAP"};
96
+    }
97
+}

+ 2
- 0
src/com/dmdirc/parser/irc/ProcessingManager.java View File

@@ -112,6 +112,8 @@ public class ProcessingManager {
112 112
         // 322
113 113
         // 323
114 114
         addProcessor(new ProcessList(parser, this));
115
+        // CAP
116
+        addProcessor(new ProcessCap(parser, this));
115 117
     }
116 118
 
117 119
     /**

+ 8
- 5
test/com/dmdirc/parser/irc/IRCParserTest.java View File

@@ -102,12 +102,15 @@ public class IRCParserTest {
102 102
         final TestParser parser = new TestParser(myInfo, new URI("irc://irc.testing.dmdirc:6667/"));
103 103
         parser.sendConnectionStrings();
104 104
 
105
-        assertEquals(2, parser.sentLines.size());
105
+        assertEquals(3, parser.sentLines.size());
106
+
107
+        assertTrue("Should send CAP LS line",
108
+                Arrays.equals(parser.getLine(0), new String[]{"CAP", "LS"}));
106 109
 
107 110
         assertTrue("Should send nickname line",
108
-                Arrays.equals(parser.getLine(0), new String[]{"NICK", "Nickname"}));
111
+                Arrays.equals(parser.getLine(1), new String[]{"NICK", "Nickname"}));
109 112
 
110
-        final String[] userParts = parser.getLine(1);
113
+        final String[] userParts = parser.getLine(2);
111 114
         assertEquals("First token should be USER", "USER", userParts[0]);
112 115
         assertEquals("USER should contain username", myInfo.getUsername().toLowerCase(),
113 116
                 userParts[1].toLowerCase());
@@ -125,10 +128,10 @@ public class IRCParserTest {
125 128
         final TestParser parser = new TestParser(myInfo, new URI("irc://password@irc.testing.dmdirc:6667/"));
126 129
         parser.sendConnectionStrings();
127 130
 
128
-        assertEquals(3, parser.sentLines.size());
131
+        assertEquals(4, parser.sentLines.size());
129 132
 
130 133
         assertTrue("Should send password line",
131
-                Arrays.equals(parser.getLine(0), new String[]{"PASS", "password"}));
134
+                Arrays.equals(parser.getLine(1), new String[]{"PASS", "password"}));
132 135
     }
133 136
 
134 137
     @Test

Loading…
Cancel
Save