KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > server > ClientConnection


1 /*- ClientConnection.java -----------------------------------------+
2  | |
3  | Copyright (C) 2002-2003 Joseph Monti, LlamaChat |
4  | countjoe@users.sourceforge.net |
5  | http://www.42llamas.com/LlamaChat/ |
6  | |
7  | This program is free software; you can redistribute it and/or |
8  | modify it under the terms of the GNU General Public License |
9  | as published by the Free Software Foundation; either version 2 |
10  | of the License, or (at your option) any later version |
11  | |
12  | This program is distributed in the hope that it will be useful, |
13  | but WITHOUT ANY WARRANTY; without even the implied warranty of |
14  | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
15  | GNU General Public License for more details. |
16  | |
17  | A copy of the GNU General Public License may be found in the |
18  | installation directory named "GNUGPL.txt" |
19  | |
20  +-----------------------------------------------------------------+
21  */

22
23 package server;
24
25 import javax.net.ssl.*;
26 import java.io.BufferedInputStream JavaDoc;
27 import java.io.BufferedOutputStream JavaDoc;
28 import java.io.ObjectOutputStream JavaDoc;
29 import java.io.ObjectInputStream JavaDoc;
30 import java.io.IOException JavaDoc;
31 import java.lang.ClassNotFoundException JavaDoc;
32 import common.*;
33 import common.sd.*;
34
35 /* -------------------- JavaDoc Information ----------------------*/
36 /**
37  * A threaded connection class to maintain the conneciton to the client
38  * a new ClientConnection must be create for each new client
39  * @author Joseph Monti <a HREF="mailto:countjoe@users.sourceforge.net">countjoe@users.sourceforge.net</a>
40  * @version 0.8
41  */

42 public class ClientConnection implements Runnable JavaDoc, SocketConnection {
43     private LlamaChatServer server;
44     private SSLSocket socket;
45     public String JavaDoc name;
46     public String JavaDoc ip;
47     public String JavaDoc channel;
48
49     private ObjectInputStream JavaDoc in;
50     private ObjectOutputStream JavaDoc out;
51     private boolean finalized;
52     private boolean admin;
53     
54     private MessageQueue queue;
55
56     ClientConnection(LlamaChatServer serv, SSLSocket sock) {
57         try {
58             name = null;
59             finalized = false;
60             admin = false;
61             channel = serv.channels.defaultChannel;
62             server = serv;
63             socket = sock;
64             ip = sock.getInetAddress().getHostName();
65             out = new ObjectOutputStream JavaDoc(sock.getOutputStream());
66             in = new ObjectInputStream JavaDoc(sock.getInputStream());
67             queue = new MessageQueue(this);
68             new Thread JavaDoc(this).start();
69         } catch (IOException JavaDoc e) {
70             server.log(this, "failed connection");
71             server.connectingUsers.remove(this);
72         }
73     }
74
75     /**
76      * Method to read an object from the client
77      * @return returns the SocketData object recieved
78      */

79     private SocketData readObject() {
80         try {
81             return (SocketData) in.readObject();
82         } catch (IOException JavaDoc e) {
83             return null;
84         } catch (ClassNotFoundException JavaDoc e) {
85             return null;
86         }
87     }
88
89     /**
90      * Method to write an object to the server via MessageQueue
91      * @param sd A SocketData object to be sent
92      */

93     public void writeObject(Object JavaDoc obj) {
94         queue.enqueue(obj);
95     }
96
97     /**
98      * Method to actually write an object to the server
99      * @param sd A SocketData object to be sent
100      */

101     public void _writeObject(Object JavaDoc obj) {
102         try {
103             out.writeObject(obj);
104             out.flush();
105         } catch (IOException JavaDoc e) {
106             close();
107         }
108     }
109
110     /**
111      * closes the connection to the client
112      */

113     public void close() {
114         server.kill(this);
115         try {
116             socket.close();
117         } catch (IOException JavaDoc e) { e.printStackTrace(); }
118     }
119
120     /**
121      * utility method to retrieve the admin status
122          * @return true if admin
123      */

124     public boolean isAdmin() {
125         return admin;
126     }
127
128 // -- Interface methods -- \\
129
/**
130      * receives server configurations
131      * @param type the type of data being sent
132      * @param obj the object being sent
133      */

134     public void serverCap(char type, Object JavaDoc obj) {
135         // does nothing ... eventually will be able to configure from client
136
}
137
138     /**
139      * used to finalize the conneciton to the client.
140      * when a user connects he must send a SD_UserAdd to tell
141      * the server the requested name
142      * @param username the name of the client
143      */

144     public void userAdd(String JavaDoc username) {
145         if (username == null) {
146             writeObject(new SD_Error("no username recieved"));
147             return;
148         }
149         if (name == null && !finalized) {
150             name = username;
151             finalized = server.finalizeUser(username, this);
152             if (!finalized) {
153                 name = null;
154                 writeObject(new SD_Kick(null));
155             }
156         } else {
157             writeObject(new SD_Error("already recieved name: " + name));
158         }
159     }
160
161     /**
162      * used by a client to attain administrative status
163      * @param password the password provided by the client
164      */

165     public void adminAdd(String JavaDoc password) {
166         if (!server.allowAdmin) {
167             writeObject(new SD_Error("admins are not allow on this server"));
168         } else if (password.equals(server.adminPass)) {
169             admin = true;
170             server.broadcast(new SD_AdminAdd(name), null, channel);
171         } else {
172             writeObject(new SD_Error("incorrect administrative password"));
173         }
174     }
175
176     /**
177      * Tells the server that the client wishes to disconnect
178      * @param username the name of the user
179      */

180     public void userDel(String JavaDoc username) {
181         close();
182     }
183
184     /**
185      * used to rename the client
186      * <i>ADD USERNAME VALIDITY CHECK</a>
187      * @param on the old name of the client
188      * @param nn the new (requested) name of the client
189      */

190     public void rename(String JavaDoc on, String JavaDoc nn) {
191         if (server.connectedUsers.containsKey(nn)) {
192             writeObject(new SD_Error("username already exists"));
193             //writeObject(new SD_Rename(nn, name));
194
} else {
195             server.connectedUsers.remove(name);
196             server.connectedUsers.put(nn, this);
197             server.broadcast(new SD_Rename(name, nn), nn, channel);
198             server.updateUserExport();
199             name = nn;
200         }
201     }
202
203     /**
204      * used to kick a user; eventually IP banning will be an added
205      * option (called ban), but will use SD_Kick
206      * @param username the name of the user to kicko
207      */

208     public void kick(String JavaDoc username) {
209         if (admin) {
210             ClientConnection cc =
211                 (ClientConnection) server.connectedUsers.get(username);
212             if (cc == null) {
213                 writeObject(new SD_Error("user " + username +
214                                                 " does not exist"));
215             } else {
216                 server.sendTo(new SD_Error("You have been kicked by " + name),
217                                                 username);
218                 cc.close();
219             }
220         } else {
221             writeObject(new SD_Error("Couldn't verify administrative status"));
222         }
223     }
224
225     /**
226      * recieves a channel change
227      * @param nc true for a new channel, if the channel exists an error is
228                     sent back to the user, otherwise the channel is created
229                     and a recursive call is made to switch the user to
230                     the new channel; if false it checks the validity of the
231                     request and move the user
232      * @param n the name of the channel
233      * @param p password for the channel, if one
234      */

235     public void channel(boolean nc, String JavaDoc n, String JavaDoc p) {
236         if (nc) {
237             String JavaDoc reason;
238             if ((reason = server.newChannel(n, p, this)) == null) {
239                 server.log(this, "channel " + n + " created");
240                 channel(false, n, p);
241             } else {
242                 writeObject(new SD_Error(reason));
243             }
244         } else {
245             if (server.channels.channelExists(n)) {
246                 if (channel.equals(n)) {
247                     writeObject(new SD_Error("Already a member of " + n));
248                     writeObject(new SD_Channel(false,null,null));
249                 } else if (!server.channels.userAdd(n, p)) {
250                     writeObject(new SD_Error("invalid passphrase or none " +
251                                 "provided, use \\join " + n + " &lt;password&gt;"));
252                     writeObject(new SD_Channel(false,null,null));
253                 } else {
254                     server.broadcast(new SD_UserDel(name), name, channel);
255                     if (server.channels.userDel(channel)) {
256                         server.broadcast(new SD_Channel(true, channel, null), null);
257                         server.chatLog(this, false);
258                         server.log(this, "channel " + channel + " removed");
259                     }
260                     channel = n;
261                     server.broadcast(new SD_UserAdd(name), name, channel);
262                     if (admin) {
263                         server.broadcast(new SD_AdminAdd(name), name, channel);
264                     }
265
266                     writeObject(new SD_Channel(false, channel, null));
267                     server.sendUserList(this);
268                     server.updateUserExport();
269                 }
270             } else {
271                 writeObject(new SD_Error(n + " does not exist"));
272                 writeObject(new SD_Channel(false,null,null));
273             }
274         }
275     }
276
277
278     /**
279      * recives a chat message from the user
280      * @param username the name of the user, not used in this case
281                         (it should be null)
282      * @param message the messsage sent by the user
283      */

284     public void chat(String JavaDoc username, String JavaDoc message) {
285         if (finalized) {
286             server.chatLog(this, message);
287             server.broadcast(new SD_Chat(name, message), name, channel);
288         } else {
289             writeObject(new SD_Error("connection not confirmed"));
290         }
291     }
292
293     /**
294      * recives a private message from the user
295      * @param username the name of the user to whom the message is sent
296      * @param message the messsage sent by the user
297      */

298     public void private_msg(String JavaDoc username, String JavaDoc message) {
299         if (finalized) {
300             server.sendTo(new SD_Private(name, message), username);
301         } else {
302             writeObject(new SD_Error("connection not confirmed"));
303         }
304     }
305
306     /**
307      * whispers to a user
308      * @param username the name of the user that the whisper is to be sent
309      * @param message the message that is to be whispered
310      */

311     public void whisper(String JavaDoc username, String JavaDoc message) {
312         if (finalized) {
313             server.sendTo(new SD_Whisper(name, message), username);
314         } else {
315             writeObject(new SD_Error("connection not confirmed"));
316         }
317     }
318
319     /**
320      * used to control the chat logging status
321      * @param start true to start logging, false to stop
322      */

323     public void chatLog(boolean start) {
324         if (admin) {
325             if (server.chatLog(this, start)) {
326                 writeObject(new SD_Log(start));
327             } else {
328                 writeObject(new SD_Error("unable to modify log for " + channel));
329             }
330        } else {
331            writeObject(new SD_Error("Could not verify administrative status"));
332        }
333     }
334
335     /**
336      * recieves an error from the client
337      * @param err the error to report
338      */

339     public void error(String JavaDoc err) {
340         server.log(this, err);
341     }
342
343 // -- Interface methods -- \\
344

345     /**
346      * Method to implement runnable, listens
347      * for incoming objects
348      */

349     public void run() {
350         SocketData sd;
351         while ((sd = readObject()) != null) {
352             sd.performAction(this);
353         }
354         close();
355     }
356 }
357
Popular Tags