]> Pileus Git - ~andy/spades/blob - src/org/pileus/spades/Message.java
51ee210505336015bfdf2bf7bfc0e07c6c1acb54
[~andy/spades] / src / org / pileus / spades / Message.java
1 package org.pileus.spades;
2
3 import java.util.Date;
4 import java.util.regex.Pattern;
5 import java.util.regex.Matcher;
6
7 public class Message
8 {
9         /* Enumerations */
10         static enum Type {
11                 OTHER,    // Unknown message type
12                 JOIN,     // Join channel
13                 PART,     // Leave channel
14                 PRIVMSG,  // Private message
15                 TOPIC,    // Display current topic
16                 NAMES,    // Display user names
17                 ERROR,    // Error message from server
18                 CAP,      // Server capabilities
19                 AUTH,     // Authentication message
20                 AUTHOK,   // Authentication succeeded
21                 AUTHFAIL, // Authentication failed
22         };
23
24         static enum How {
25                 OTHER,    // Unknown message type
26                 CHANNEL,  // Normal message to a channel
27                 MENTION,  // User was mentioned in message text
28                 DIRECT,   // Message directed towards user
29                 PRIVMSG,  // Private message to user only
30                 SENT      // Message was sent by the user
31         };
32
33         /* Constants */
34         private static final String  reMsg  = "(:([^ ]+) +)?(([A-Z0-9]+) +)(([^ ]+)[= ]+)?(([^: ]+) *)?(:(.*))?";
35         private static final String  reFrom = "([^! ]+)!.*";
36         private static final String  reTo   = "(([^ :,]*)[:,] *)?(.*)";
37         private static final String  reCmd  = "/([a-z]+)( +(.*))?";
38
39         private static final Pattern ptMsg  = Pattern.compile(reMsg);
40         private static final Pattern ptFrom = Pattern.compile(reFrom);
41         private static final Pattern ptTo   = Pattern.compile(reTo);
42         private static final Pattern ptCmd  = Pattern.compile(reCmd);
43
44         /* Public data */
45         public Date    time = null;
46
47         public String  line = "";
48
49         public String  src  = "";
50         public String  cmd  = "";
51         public String  dst  = "";
52         public String  arg  = "";
53         public String  msg  = "";
54
55         public Type    type = Type.OTHER;
56         public How     how  = How.OTHER;
57         public String  from = "";
58         public String  to   = "";
59         public String  txt  = "";
60
61         /* Static methods */
62         public static String clean(String msg)
63         {
64                 String num = "0?[0-9]|1[0-5]";
65                 return msg.replaceAll("[\\002\\011\\017\\025]", "")
66                           .replaceAll("[\\003\\013]("+num+")(,"+num+")?", "");
67         }
68
69         /* Public Methods */
70         public Message(String dst, String from, String msg)
71         {
72                 this.time = new Date();
73                 this.how  = How.SENT;
74                 this.from = from;
75
76                 if (this.parseSlash(msg))
77                         return;
78
79                 this.type = Type.PRIVMSG;
80                 this.cmd  = "PRIVMSG";
81                 this.dst  = dst;
82                 this.msg  = msg;
83                 this.line = this.cmd + " " + this.dst + " :" + this.msg;
84         }
85
86         public Message(String line, String name)
87         {
88                 this.time = new Date();
89
90                 this.parseText(line);
91                 this.parseTypes(name);
92         }
93
94         public void debug()
95         {
96                 Os.debug("---------------------");
97                 Os.debug("line = [" + line + "]");
98                 Os.debug("src  = " + this.src);
99                 Os.debug("cmd  = " + this.cmd);
100                 Os.debug("dst  = " + this.dst);
101                 Os.debug("arg  = " + this.arg);
102                 Os.debug("msg  = " + this.msg);
103                 Os.debug("from = " + this.from);
104                 Os.debug("to   = " + this.to);
105                 Os.debug("txt  = " + this.txt);
106                 Os.debug("---------------------");
107         }
108
109         public String toString()
110         {
111                 return this.from + ": " + this.txt;
112         }
113
114         /* Private methods */
115         private String notnull(String string)
116         {
117                 return string == null ? "" : string;
118         }
119
120         private boolean parseSlash(String msg)
121         {
122                 if (msg.charAt(0) != '/')
123                         return false;
124
125                 // Split up line
126                 Matcher mr = ptCmd.matcher(msg);
127                 if (!mr.matches())
128                         return false;
129
130                 String cmd = notnull(mr.group(1));
131                 String arg = notnull(mr.group(3));
132
133                 // Parse commands
134                 if (cmd.matches("join")) {
135                         Os.debug("Message: /join");
136                         this.type = Type.JOIN;
137                         this.cmd  = "JOIN";
138                         this.msg  = arg;
139                         this.line = this.cmd + " :" + arg;
140                 }
141
142                 if (cmd.matches("part")) {
143                         Os.debug("Message: /part");
144                         this.type = Type.PART;
145                         this.cmd  = "PART";
146                         this.msg  = arg;
147                         this.line = this.cmd + " :" + arg;
148                 }
149
150                 // Print warning if command is not recognized
151                 if (this.line == null)
152                         Os.debug("Message: unknown command");
153
154                 return true;
155         }
156
157         private void parseText(String line)
158         {
159                 // Cleanup line
160                 line = line.replaceAll("\\s+",       " ");
161                 line = line.replaceAll("^ | $",      "");
162                 this.line = line;
163
164                 // Split line into parts
165                 Matcher mrMsg = ptMsg.matcher(line);
166                 if (mrMsg.matches()) {
167                         this.src  = notnull(mrMsg.group(2));
168                         this.cmd  = notnull(mrMsg.group(4));
169                         this.dst  = notnull(mrMsg.group(6));
170                         this.arg  = notnull(mrMsg.group(8));
171                         this.msg  = notnull(mrMsg.group(10));
172                 }
173
174                 // Determine friendly parts
175                 Matcher mrFrom = ptFrom.matcher(this.src);
176                 if (mrFrom.matches())
177                         this.from = notnull(mrFrom.group(1));
178
179                 Matcher mrTo = ptTo.matcher(this.msg);
180                 if (mrTo.matches())
181                         this.to   = notnull(mrTo.group(2));
182
183                 if (this.to.equals(""))
184                         this.txt  = notnull(this.msg);
185                 else
186                         this.txt  = notnull(mrTo.group(3));
187         }
188
189         private void parseTypes(String name)
190         {
191                 // Parse commands names
192                 if      (this.cmd.equals("PRIVMSG"))       this.type = Type.PRIVMSG;
193                 else if (this.cmd.equals("332"))           this.type = Type.TOPIC;
194                 else if (this.cmd.equals("353"))           this.type = Type.NAMES;
195                 else if (this.cmd.equals("ERROR"))         this.type = Type.ERROR;
196                 else if (this.cmd.equals("CAP"))           this.type = Type.CAP;
197                 else if (this.cmd.equals("AUTHENTICATE"))  this.type = Type.AUTH;
198                 else if (this.cmd.equals("903"))           this.type = Type.AUTHOK;
199                 else if (this.cmd.equals("904"))           this.type = Type.AUTHFAIL;
200                 else if (this.cmd.equals("905"))           this.type = Type.AUTHFAIL;
201                 else if (this.cmd.equals("906"))           this.type = Type.AUTHFAIL;
202                 else if (this.cmd.equals("907"))           this.type = Type.AUTHFAIL;
203
204                 // Set directed
205                 if      (this.dst.equals(name))            this.how  = How.PRIVMSG;
206                 else if (this.to.equals(name))             this.how  = How.DIRECT;
207                 else if (this.msg.contains(name))          this.how  = How.MENTION;
208                 else if (this.type == Type.PRIVMSG)        this.how  = How.CHANNEL;
209         }
210 }