View Javadoc

1   /*
2    *  PCUServeur for the PCU project.
3    *  Copyright (C) 2010  PLU Julien
4    *
5    *  This program is free software: you can redistribute it and/or modify
6    *  it under the terms of the GNU General Public License as published by
7    *  the Free Software Foundation, either version 3 of the License, or
8    *  (at your option) any later version.
9    *  
10   *  This program is distributed in the hope that it will be useful,
11   *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12   *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13   *  GNU General Public License for more details.
14   *
15   *  You should have received a copy of the GNU General Public License
16   *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
17   *  
18   *  For questions: julien.plu@redaction-developpez.com
19   */
20  package pcuserveur.lib;
21  
22  import java.io.BufferedReader;
23  import java.io.BufferedWriter;
24  import java.io.IOException;
25  import java.io.InputStreamReader;
26  import java.io.OutputStreamWriter;
27  import java.net.Socket;
28  import java.net.UnknownHostException;
29  import java.security.NoSuchAlgorithmException;
30  import java.sql.SQLException;
31  import java.util.ArrayList;
32  import java.util.Collections;
33  import java.util.HashMap;
34  import java.util.HashSet;
35  import java.util.List;
36  import java.util.Set;
37  import java.util.Map.Entry;
38  
39  /**
40   * @author PLU Julien
41   * @version 1.0 
42   * 
43   * <b>
44   *     Cette classe implémente le protocole PCU et prend en charge
45   *     la connexion entre le serveur et le client. 
46   * </b>
47   * <p>
48   *     Un GestionnaireConnexion est caractérisé par les informations
49   *     suivantes:
50   *     <ul>
51   *         <li>Code du caractère CR.</li>
52   *         <li>Code du caractère CRLF.</li>
53   *         <li>Code de la séquence LF.</li>
54   *         <li>Un Utilisateur associé au gestionnaire de connexion.</li>
55   *         <li>Un flux d'entrée du gestionnaire de connexion.</li>
56   *         <li>Un Set contenant les états dans lequel ce trouve l'utilisateur.</li>
57   *         <li>Un boolean représentant le fonctionnement du thread.</li>
58   *         <li>Une HashMap ayant un String pour clef et un Canal pour valeur.</li>
59   *         <li>Un int pour le numéro du gestionnaire de connexion.</li>
60   *         <li>Un serveur.</li>
61   *         <li>Une Socket.</li>
62   *         <li>Flux de sortie du gestionnaire de connexion.</li>
63   *         <li>Une ArrayListe pour la liste des login des client pour lesquels
64   *          on a accepté les connexion directe accepte.</li>
65   *         <li>Une ArrayListe pour la liste des login des client pour lesquels
66   *          on a refusé les connexion directe accepte.</li>
67   *     </ul>
68   * </p>
69   * 
70   * @see Runnable
71   * @see Vide
72   * @see Utilisateur
73   * @see Etat
74   * @see Canal
75   * @see Serveur
76   * @see MonLog
77   * @see DejaConnecteException
78   * @see CanalExistantException
79   * @see CommandeIncorrecteException
80   * @see LoginIntrouvableException
81   * @see NonConnecteException
82   * @see NbCanauxMaxException
83   */
84  public class GestionnaireConnexion implements Vide , Runnable {
85  	/**
86  	 * <p>
87  	 * Caractère représentant le caractère "Cariage Return".
88  	 * </p>
89  	 * 
90  	 * @see GestionnaireConnexion#lister (String)
91  	 * @see GestionnaireConnexion#membre (String)
92  	 * @see GestionnaireConnexion#srv_lister ()
93  	 * @see Serveur#informationMembre (String)
94  	 * @see Serveur#listerCanaux (String)
95  	 * @see Serveur#listerServeur ()
96  	 */
97  	public static final char CR = '\r';
98  	/**
99  	 * <p>
100 	 * Caractère représentant la chaîne "Cariage Return Line Feed".
101 	 * </p>
102 	 * 
103 	 * @see GestionnaireConnexion#envoyer (String)
104 	 */
105 	private static final String CRLF = GestionnaireConnexion.CR + "" + GestionnaireConnexion.LF; //$NON-NLS-1$
106 	/**
107 	 * <p>
108 	 * Caractère représentant le caractère "Line Feed".
109 	 * </p>
110 	 */
111 	private static final char LF = '\n';
112 	/**
113 	 * <p>
114 	 * Utilisateur correspondant au gestionnaire de connexion actuel.
115 	 * </p>
116 	 * 
117 	 * @see GestionnaireConnexion#cnl_changerSujet (String, String)
118 	 * @see GestionnaireConnexion#cnl_creer (String, String)
119 	 * @see GestionnaireConnexion#cnl_supprimer (String)
120 	 * @see GestionnaireConnexion#getClient ()
121 	 * @see GestionnaireConnexion#message (String, String)
122 	 * @see GestionnaireConnexion#quitter (String)
123 	 * @see GestionnaireConnexion#run ()
124 	 * @see GestionnaireConnexion#srv_lister ()
125 	 * @see GestionnaireConnexion#srv_relancer(String)
126 	 * @see GestionnaireConnexion#stopper (String)
127 	 * @see GestionnaireConnexion#utl_ejecter (String, String)
128 	 * @see GestionnaireConnexion#vider ()
129 	 */
130 	private final Utilisateur client = new Utilisateur ();
131 	/**
132 	 * <p>
133 	 * Flux d'entrée du gestionnaire de connexion actuel.
134 	 * </p>
135 	 * 
136 	 * @see GestionnaireConnexion#initialisationGestionnaire (Socket, Serveur,
137 	 *      int)
138 	 * @see GestionnaireConnexion#run ()
139 	 * @see GestionnaireConnexion#vider ()
140 	 */
141 	private BufferedReader entree;
142 	/**
143 	 * <p>
144 	 * Etat(s) de l'utilisateur actuel.
145 	 * </p>
146 	 * 
147 	 * @see GestionnaireConnexion#cnl_changerSujet (String, String)
148 	 * @see GestionnaireConnexion#cnl_creer (String, String)
149 	 * @see GestionnaireConnexion#cnl_supprimer (String)
150 	 * @see GestionnaireConnexion#identifier (String, String)
151 	 * @see GestionnaireConnexion#infoMembre (String)
152 	 * @see GestionnaireConnexion#initialisationGestionnaire (Socket, Serveur,
153 	 *      int)
154 	 * @see GestionnaireConnexion#lister (String)
155 	 * @see GestionnaireConnexion#membre (String)
156 	 * @see GestionnaireConnexion#message (String, String)
157 	 * @see GestionnaireConnexion#quitter (String)
158 	 * @see GestionnaireConnexion#quitterCanal (String)
159 	 * @see GestionnaireConnexion#rejoindre (String)
160 	 * @see GestionnaireConnexion#srv_lister ()
161 	 * @see GestionnaireConnexion#srv_relancer (String)
162 	 * @see GestionnaireConnexion#srv_stopper (String)
163 	 * @see GestionnaireConnexion#utl_ejecter (String, String)
164 	 * @see GestionnaireConnexion#vider ()
165 	 */
166 	private final Set<Etat> etats = new HashSet<Etat> ();
167 	/**
168 	 * <p>
169 	 * Gestion du thread.
170 	 * </p>
171 	 * 
172 	 * @see GestionnaireConnexion#initialisationGestionnaire (Socket, Serveur,
173 	 *      int)
174 	 * @see GestionnaireConnexion#run ()
175 	 * @see GestionnaireConnexion#setLance (boolean)
176 	 * @see GestionnaireConnexion#vider ()
177 	 */
178 	private boolean lance = true;
179 	/**
180 	 * <p>
181 	 * Liste des canaux ou l'utilisateur actuel se situe.
182 	 * </p>
183 	 * 
184 	 * @see GestionnaireConnexion#enleverCanal (String)
185 	 * @see GestionnaireConnexion#infoCanaux ()
186 	 * @see GestionnaireConnexion#membre (String)
187 	 * @see GestionnaireConnexion#message (String, String)
188 	 * @see GestionnaireConnexion#quitter (String)
189 	 * @see GestionnaireConnexion#quitterCanal (String)
190 	 * @see GestionnaireConnexion#rejoindre (String)
191 	 * @see GestionnaireConnexion#vider ()
192 	 */
193 	private final HashMap<String, Canal> listeCanaux = new HashMap<String, Canal> ();
194 	/**
195 	 * <p>
196 	 * Liste des login avec lesquels on a accepté les connections directes
197 	 * </p>
198 	 * 
199 	 * @see GestionnaireConnexion#connexionDirecte (String, String)
200 	 * @see GestionnaireConnexion#connexionDirecteAccepte (String, String, String)
201 	 * @see GestionnaireConnexion#connexionDirecteRefuse (String)
202 	 */
203 	private final ArrayList<String> listeNomAccepte = new ArrayList<String> ();
204 	/**
205 	 * <p>
206 	 * Liste des login avec lesquels on a refusé les connections directes
207 	 * </p>
208 	 * 
209 	 * @see GestionnaireConnexion#connexionDirecte (String, String)
210 	 * @see GestionnaireConnexion#connexionDirecteAccepte (String, String, String)
211 	 * @see GestionnaireConnexion#connexionDirecteRefuse (String)
212 	 */
213 	private final ArrayList<String> listeNomRefuse = new ArrayList<String> ();
214 	/**
215 	 * <p>
216 	 * Numéro du gestionnaire de connexion actuel dans la liste du serveur.
217 	 * </p>
218 	 * 
219 	 * @see GestionnaireConnexion#initialisationGestionnaire (Socket, Serveur,
220 	 *      int)
221 	 * @see GestionnaireConnexion#quitter (String)
222 	 * @see GestionnaireConnexion#vider ()
223 	 */
224 	private int numeroGC;
225 	/**
226 	 * <p>
227 	 * Serveur auquel le gestionnaire de connexion actuel est connecté.
228 	 * </p>
229 	 * 
230 	 * @see GestionnaireConnexion#cnl_changerSujet (String, String)
231 	 * @see GestionnaireConnexion#cnl_creer (String, String)
232 	 * @see GestionnaireConnexion#cnl_supprimer (String)
233 	 * @see GestionnaireConnexion#identifier (String, String)
234 	 * @see GestionnaireConnexion#infoMembre (String)
235 	 * @see GestionnaireConnexion#initialisationGestionnaire (Socket, Serveur,
236 	 *      int)
237 	 * @see GestionnaireConnexion#lister (String)
238 	 * @see GestionnaireConnexion#membre (String)
239 	 * @see GestionnaireConnexion#message (String, String)
240 	 * @see GestionnaireConnexion#quitter (String)
241 	 * @see GestionnaireConnexion#quitterCanal (String)
242 	 * @see GestionnaireConnexion#rejoindre (String)
243 	 * @see GestionnaireConnexion#srv_lister ()
244 	 * @see GestionnaireConnexion#srv_relancer (String)
245 	 * @see GestionnaireConnexion#srv_stopper (String)
246 	 * @see GestionnaireConnexion#utl_ejecter (String, String)
247 	 * @see GestionnaireConnexion#vider ()
248 	 */
249 	private Serveur serveur;
250 
251 	/**
252 	 * <p>
253 	 * Socket sur lequel le gestionnaire de connexion recevra et émettra les
254 	 * données.
255 	 * </p>
256 	 * 
257 	 * @see GestionnaireConnexion#estVide ()
258 	 * @see GestionnaireConnexion#getIp ()
259 	 * @see GestionnaireConnexion#initialisationGestionnaire (Socket, Serveur,
260 	 *      int)
261 	 * @see GestionnaireConnexion#vider ()
262 	 */
263 	private Socket socket;
264 
265 	/**
266 	 * <p>
267 	 * Flux de sortie du gestionnaire de connexion actuel.
268 	 * </p>
269 	 * 
270 	 * @see GestionnaireConnexion#envoyer (String)
271 	 * @see GestionnaireConnexion#initialisationGestionnaire (Socket, Serveur,
272 	 *      int)
273 	 * @see GestionnaireConnexion#run ()
274 	 * @see GestionnaireConnexion#vider ()
275 	 */
276 	private BufferedWriter sortie;
277 
278 	/**
279 	 * <p>
280 	 * Constructeur par défaut.
281 	 * </p>
282 	 */
283 	public GestionnaireConnexion () {
284 		// Constructeur par defaut.
285 	}
286 
287 	/**
288 	 * <p>
289 	 * Analyse des messages envoyés par le client.
290 	 * </p>
291 	 * 
292 	 * @param message
293 	 *            Message envoyé par le client à analyser.
294 	 *            
295 	 * @return La Liste contenant l'analyse final du message envoyé par
296 	 *         le client.
297 	 *         
298 	 * @throws CommandeIncorrecteException
299 	 *             La commande rentrée est incorrect.
300 	 * @throws IOException
301 	 *             Un envoie à un client a échoué.
302 	 */
303 	private synchronized List<String> analyseMessage (final String message) throws CommandeIncorrecteException, IOException {
304 		final List<String> res = Collections.synchronizedList (new ArrayList<String> ());
305 		final StringBuffer tmp = new StringBuffer ();
306 		boolean b = false;
307 		int i = 0, nbg = 0;
308 
309 		if (message == null) {
310 			throw new IOException ();
311 		}
312 		// On compte le nombre de guillemets
313 		while (i < message.length ()) {
314 			if (message.charAt (i) == '"') {
315 				nbg++;
316 			}
317 			i++;
318 		}
319 		// Si celui ci est impair on leve une exception
320 		if (nbg % 2 != 0) {
321 			throw new CommandeIncorrecteException ();
322 		}
323 
324 		i = 0;
325 
326 		// On parcours toute la chaine
327 		while (i < message.length ()) {
328 			// Si on tombe sur un guillemet on bascule le booleen b et on avance
329 			if (message.charAt (i) == '"') {
330 				b = !b;
331 				i++;
332 			}
333 			// si on est a l'interieur de guillemets on memorise tout jusqu'au
334 			// prochain guillemet
335 			if (b) {
336 				while ((i < message.length ()) && (message.charAt (i) != '"')) {
337 					tmp.append (message.charAt (i));
338 					i++;
339 				}
340 				res.add (tmp.toString ());
341 				tmp.delete (0, tmp.length ());
342 			}
343 			else {
344 				// tant qu'on trouve des espaces on avance
345 				while ((i < message.length ()) && (message.charAt (i) == ' ')) {
346 					i++;
347 				}
348 				// tant qu'il n'y a pas d'espace ni de guillemet on avance et on
349 				// memorise
350 				while ((i < message.length ()) && (message.charAt (i) != ' ') && (message.charAt (i) != '"')) {
351 					tmp.append (message.charAt (i));
352 					i++;
353 				}
354 				// Si on a memorise quelquechose on le met dans le vecteur
355 				if (!tmp.toString ().equals ("")) {//$NON-NLS-1$
356 					res.add (tmp.toString ());
357 				}
358 				tmp.delete (0, tmp.length ());
359 			}
360 		}
361 		if (res.size () == 0) {
362 			throw new CommandeIncorrecteException ();
363 		}
364 
365 		return res;
366 	}
367 
368 	/**
369 	 * <p>
370 	 * Changer le sujet d'un canal.
371 	 * </p>
372 	 * 
373 	 * @param nom
374 	 *            Nom du canal qui verra son sujet changé.
375 	 * @param sujet
376 	 *            Nouveau sujet du canal.
377 	 * @throws IOException
378 	 *             Un envoie à un client a échoué.
379 	 */
380 	private synchronized void cnl_changerSujet (final String nom, final String sujet) throws IOException {
381 		String reponse = ""; //$NON-NLS-1$
382 
383 		if (this.etats.contains (Etat.authentifie)) {
384 			if (this.client.estAdministrateur ()) {
385 				try {
386 					this.serveur.changerSujetCanal (nom, sujet);
387 
388 					reponse = "+OK_CNL_CHANGERSUJET " + nom + " \"" + sujet + "\""; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
389 				}
390 				catch (final CanalInexistantException e) {
391 					reponse = "-ERR_CANALINTROUVABLE"; //$NON-NLS-1$
392 				}
393 				reponse += " " + nom; //$NON-NLS-1$
394 			}
395 			else {
396 				reponse = "-ERR_NONADMINISTRATEUR"; //$NON-NLS-1$
397 			}
398 		}
399 		else {
400 			reponse = "-ERR_ETAT"; //$NON-NLS-1$
401 		}
402 		this.envoyer (reponse);
403 	}
404 
405 	/**
406 	 * <p>
407 	 * Creer un nouveau canal.
408 	 * </p>
409 	 * 
410 	 * @param nom
411 	 *            Nom du nouveau canal.
412 	 * @param sujet
413 	 *            Sujet du nouveau canal.
414 	 * @throws IOException
415 	 *             Un envoie à un client a échoué.
416 	 */
417 	private synchronized void cnl_creer (final String nom, final String sujet) throws IOException {
418 		String reponse = ""; //$NON-NLS-1$
419 		boolean nbc = false;
420 
421 		if (this.etats.contains (Etat.authentifie)) {
422 			if (this.client.estAdministrateur ()) {
423 				try {
424 					this.serveur.creerCanal (nom, sujet);
425 
426 					reponse = "+OK_CNL_CREER " + nom + " \"" + sujet + "\""; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
427 				}
428 				catch (final CanalExistantException e) {
429 					reponse = "-ERR_CANALEXISTANT"; //$NON-NLS-1$
430 				}
431 				catch (final NbCanauxMaxException e1) {
432 					nbc = true;
433 				}
434 			}
435 			else {
436 				reponse = "-ERR_NONADMINISTRATEUR"; //$NON-NLS-1$
437 			}
438 		}
439 		else {
440 			reponse = "-ERR_ETAT"; //$NON-NLS-1$
441 		}
442 		if (nbc) {
443 			reponse = "-ERR_NBCANAUXMAX"; //$NON-NLS-1$
444 		}
445 		this.envoyer (reponse);
446 	}
447 
448 	/**
449 	 * <p>
450 	 * Suppresion d'un canal.
451 	 * </p>
452 	 * 
453 	 * @param nom
454 	 *            Nom du canal à supprimer.
455 	 * @throws IOException
456 	 *            Un envoie à un client a échoué.
457 	 */
458 	private synchronized void cnl_supprimer (final String nom) throws IOException {
459 		String reponse = ""; //$NON-NLS-1$
460 
461 		if (this.etats.contains (Etat.authentifie)) {
462 			if (this.client.estAdministrateur ()) {
463 				try {
464 					this.serveur.supprimerCanal (nom);
465 
466 					reponse = "+OK_CNL_SUPPRIMER"; //$NON-NLS-1$
467 				}
468 				catch (final CanalInexistantException e) {
469 					reponse = "-ERR_CANALINTROUVABLE"; //$NON-NLS-1$
470 				}
471 				reponse += " " + nom; //$NON-NLS-1$
472 			}
473 			else {
474 				reponse = "-ERR_NONADMINISTRATEUR"; //$NON-NLS-1$
475 			}
476 		}
477 		else {
478 			reponse = "-ERR_ETAT"; //$NON-NLS-1$
479 		}
480 		this.envoyer (reponse);
481 	}
482 
483 	/**
484 	 * <p>
485 	 * Demande de connexion directe avec quelqu'un.
486 	 * </p>
487 	 * 
488 	 * @param login
489 	 *            Login de la personne avec laquelle on veut une connexion.
490 	 * @param ip
491 	 *            Ip de la personne qui demande la connexion directe.
492 	 * @throws IOException
493 	 *             Un envoie à un client a échoué.
494 	 */
495 	public synchronized void connexionDirecte (final String login, final String ip) throws IOException {
496 		String reponse = ""; //$NON-NLS-1$
497 
498 		if (this.etats.contains (Etat.authentifie)) {
499 			try {
500 				if (!this.listeNomAccepte.contains (login)) {
501 					if (this.listeNomRefuse.contains (login)) {
502 						this.listeNomRefuse.remove (login);
503 					}
504 					GestionnaireConnexion gc = new GestionnaireConnexion ();
505 					
506 					gc = this.serveur.connexion_directe (login);
507 
508 					gc.envoyer ("CONNEXIONDIRECTE " + this.client.getLogin () + " " + ip); //$NON-NLS-1$//$NON-NLS-2$
509 
510 					this.listeNomAccepte.add (login);
511 
512 					gc = null;
513 				}
514 			}
515 			catch (final LoginIntrouvableException e) {
516 				reponse = "-ERR_LOGININTROUVABLE " + login; //$NON-NLS-1$
517 			}
518 		}
519 		else {
520 			reponse = "-ERR_ETAT"; //$NON-NLS-1$
521 		}
522 		this.envoyer (reponse);
523 	}
524 
525 	/**
526 	 * <p>
527 	 * Acceptation d'une connexion directe avec quelqu'un.
528 	 * </p>
529 	 * 
530 	 * @param login
531 	 *            Login de la personne avec laquelle on veut une connexion.
532 	 * @param ip
533 	 *            Ip de la personne qui demande la connexion directe.
534 	 * @param port_connexion
535 	 *            Port sur lequel la connexion sera établie.
536 	 * @throws IOException
537 	 *             Un envoie à un client a échoué.
538 	 */
539 	public synchronized void connexionDirecteAccepte (final String login, final String ip, final String port_connexion) throws IOException {
540 		String reponse = ""; //$NON-NLS-1$
541 
542 		if (this.etats.contains (Etat.authentifie)) {
543 			try {
544 				if (!this.listeNomAccepte.contains (login)) {
545 					if (this.listeNomRefuse.contains (login)) {
546 						this.listeNomRefuse.remove (login);
547 					}
548 					this.listeNomAccepte.add (login);
549 					this.etats.add (Etat.connexion_directe);
550 
551 					GestionnaireConnexion gc = new GestionnaireConnexion ();
552 					
553 					gc = this.serveur.connexion_directe_accepte (login);
554 
555 					gc.envoyer ("+OK_CONNEXIONDIRECTE " + ip + " " + port_connexion); //$NON-NLS-1$//$NON-NLS-2$
556 
557 					gc = null;
558 				}
559 			}
560 			catch (final LoginIntrouvableException e) {
561 				reponse = "-ERR_LOGININTROUVABLE " + login; //$NON-NLS-1$
562 			}
563 		}
564 		else {
565 			reponse = "-ERR_ETAT"; //$NON-NLS-1$
566 		}
567 		this.envoyer (reponse);
568 	}
569 
570 	/**
571 	 * <p>
572 	 * Refus d'une connexion directe avec quelqu'un.
573 	 * </p>
574 	 * 
575 	 * @param login
576 	 *            Login de la personne avec laquelle on veut une connexion.
577 	 * @throws IOException
578 	 *             Un envoie à un client a échoué.
579 	 */
580 	public synchronized void connexionDirecteRefuse (final String login) throws IOException {
581 		String reponse = ""; //$NON-NLS-1$
582 
583 		if (this.etats.contains (Etat.authentifie)) {
584 			try {
585 				if (!this.listeNomRefuse.contains (login)) {
586 					this.listeNomRefuse.add (login);
587 					this.etats.add (Etat.connexion_directe);
588 					
589 					GestionnaireConnexion gc = new GestionnaireConnexion ();
590 
591 					gc = this.serveur.connexion_directe_refuse (login);
592 
593 					gc.envoyer ("+KO_CONNEXIONDIRECTE " + login); //$NON-NLS-1$
594 					gc.enleverNom (login);
595 
596 					gc = null;
597 				}
598 			}
599 			catch (final LoginIntrouvableException e) {
600 				reponse = "-ERR_LOGININTROUVABLE " + login; //$NON-NLS-1$
601 			}
602 		}
603 		else {
604 			reponse = "-ERR_ETAT"; //$NON-NLS-1$
605 		}
606 		this.envoyer (reponse);
607 	}
608 
609 	/**
610 	 * <p>
611 	 * Enlever un canal de la liste des canaux ou se situe l'utilisateur.
612 	 * </p>
613 	 * 
614 	 * @param nom_canal
615 	 *            Nom du canal à enlever de la liste.
616 	 */
617 	public void enleverCanal (final String nom_canal) {
618 		this.listeCanaux.remove (nom_canal);
619 	}
620 
621 	/**
622 	 * <p>
623 	 * Enlever un nom dans la liste des clients acceptés.
624 	 * </p>
625 	 * 
626 	 * @param login
627 	 * 			Login à retirer.
628 	 */
629 	public void enleverNom (final String login) {
630 		this.listeNomAccepte.remove (login);
631 	}
632 
633 	/**
634 	 * <p>
635 	 * Envoyer un message.
636 	 * </p>
637 	 * 
638 	 * @param message
639 	 *            Message à envoyer.
640 	 * @throws IOException
641 	 *             Un envoie à un client a échoué.
642 	 */
643 	public synchronized void envoyer (final String message) throws IOException {
644 		this.sortie.write (message + GestionnaireConnexion.CRLF);
645 		this.sortie.flush ();
646 	}
647 
648 	/**
649 	 * <p>
650 	 * Savoir si un GestionnaireConnexion est vide, c'est à dire si il est
651 	 * inutilisé.
652 	 * </p>
653 	 * 
654 	 * @return true si le GestionnaireConnexion est vide, false sinon.
655 	 */
656 	public synchronized boolean estVide () {
657 		return this.socket == null;
658 	}
659 
660 	/**
661 	 * <p>
662 	 * Renvoie le client courant.
663 	 * </p>
664 	 * 
665 	 * @return Le client.
666 	 */
667 	public synchronized Utilisateur getClient () {
668 		return this.client;
669 	}
670 
671 	/**
672 	 * <p>
673 	 * Renvoie l'adresse IP du client.
674 	 * </p>
675 	 * 
676 	 * @return L'adresse IP.
677 	 */
678 	public String getIp () {
679 		return this.socket.getInetAddress ().toString ().substring (1);
680 	}
681 
682 	/**
683 	 * <p>
684 	 * Identification du client dans la base de donnée.
685 	 * </p>
686 	 * 
687 	 * @param login
688 	 *            Login du client.
689 	 * @param mdp
690 	 *            Mot de passe du client.
691 	 * @throws IOException
692 	 *             Un envoie à un client a échoué.
693 	 */
694 	private synchronized void identifier (final String login, final String mdp) throws IOException {
695 		String reponse = ""; //$NON-NLS-1$
696 
697 		if (this.etats.contains (Etat.non_authentifie)) {
698 			try {
699 				this.serveur.verifierLoginMdp (login, mdp, this.client);
700 				this.etats.remove (Etat.non_authentifie);
701 				this.etats.add (Etat.authentifie);
702 				reponse = "+OK_IDENTIFIER " + login + " " + (this.client.estAdministrateur () ? "admin" : "nonadmin"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
703 			}
704 			catch (final SQLException e) {
705 				Serveur.logServeur.logMessage ("Erreur avec la base de donnée"); //$NON-NLS-1$
706 				Serveur.logServeur.logException ("GestionnaireConnexion", "identifier", e); //$NON-NLS-1$ //$NON-NLS-2$
707 				reponse = "-ERR_INTERNE"; //$NON-NLS-1$
708 			}
709 			catch (final IdentifierException e) {
710 				reponse = "-ERR_ECHECIDENT"; //$NON-NLS-1$
711 				Serveur.logCoDeco.logMessage (login + " n'a pas pu se connecté"); //$NON-NLS-1$
712 			}
713 			catch (final NoSuchAlgorithmException e) {
714 				Serveur.logServeur.logMessage ("Algorithme non trouvé"); //$NON-NLS-1$
715 				Serveur.logServeur.logException ("GestionnaireConnexion", "identifier", e); //$NON-NLS-1$ //$NON-NLS-2$
716 				reponse = "-ERR_INTERNE"; //$NON-NLS-1$
717 			}
718 		}
719 		else {
720 			reponse = "-ERR_ETAT"; //$NON-NLS-1$
721 		}
722 		this.envoyer (reponse);
723 	}
724 
725 	/**
726 	 * <p>
727 	 * Renvoie le nom des canaux auxquels le client est connecté.
728 	 * </p>
729 	 * 
730 	 * @return Chaine des nom de canaux.
731 	 */
732 	public String infoCanaux () {
733 		final StringBuffer res = new StringBuffer ();
734 		final int i = 0;
735 
736 		for (final Entry<String, Canal> entry:this.listeCanaux.entrySet ()) {
737 			final Canal valeur = entry.getValue ();
738 
739 			res.append (valeur.getNom ());
740 			if (i != this.listeCanaux.size () - 1) {
741 				res.append (" "); //$NON-NLS-1$
742 			}
743 		}
744 
745 		return res.toString ();
746 	}
747 
748 	/**
749 	 * <p>
750 	 * Connaitre les informations de tout les utilisateurs connectés au serveur.
751 	 * </p>
752 	 * 
753 	 * @param login
754 	 *            Login de l'utilisateur dont on veut connaître les
755 	 *            informations.
756 	 * @throws IOException
757 	 *             Un envoie à un client a échoué.
758 	 */
759 	private synchronized void infoMembre (final String login) throws IOException {
760 		String reponse = ""; //$NON-NLS-1$
761 
762 		if (this.etats.contains (Etat.authentifie)) {
763 			try {
764 				reponse = "+OK_INFOMEMBRE " + this.serveur.informationMembre (login); //$NON-NLS-1$
765 			}
766 			catch (final LoginIntrouvableException e) {
767 				reponse = "-ERR_LOGININTROUVABLE " + login; //$NON-NLS-1$
768 			}
769 		}
770 		else {
771 			reponse = "-ERR_ETAT"; //$NON-NLS-1$
772 		}
773 		this.envoyer (reponse);
774 	}
775 
776 	/**
777 	 * <p>
778 	 * Initialise le gestionnaire de connexion.
779 	 * </p>
780 	 * 
781 	 * @param socket1
782 	 *            Socket ou le gestionnaire de connexion sera connecté.
783 	 * @param serveur1
784 	 *            Serveur sur lequel le gestionnaire de connexion sera connecté.
785 	 * @param numeroGC1
786 	 *            Numéro du gestionnaire de connexion dans le serveur.
787 	 */
788 	public synchronized void initialisationGestionnaire (final Socket socket1, final Serveur serveur1, final int numeroGC1) {
789 		this.socket = socket1;
790 		this.serveur = serveur1;
791 		this.numeroGC = numeroGC1;
792 		this.lance = true;
793 
794 		try {
795 			this.etats.add (Etat.non_authentifie);
796 			this.sortie = new BufferedWriter (new OutputStreamWriter (this.socket.getOutputStream (), "UTF-8")); //$NON-NLS-1$
797 			this.entree = new BufferedReader (new InputStreamReader (this.socket.getInputStream (), "UTF-8")); //$NON-NLS-1$
798 		}
799 		catch (final UnknownHostException e) {
800 			Serveur.logServeur.logMessage ("Hote inconnu"); //$NON-NLS-1$
801 			Serveur.logServeur.logException ("GestionnaireConnexion", "initialisationGestionnaire", e); //$NON-NLS-1$//$NON-NLS-2$
802 		}
803 		catch (final IOException e) {
804 			Serveur.logServeur.logMessage ("Erreur E/S lors de la mise en service du socket"); //$NON-NLS-1$
805 			Serveur.logServeur.logException ("GestionnaireConnexion", "initialisationGestionnaire", e); //$NON-NLS-1$//$NON-NLS-2$
806 		}
807 		catch (final NullPointerException e) {
808 			Serveur.logServeur.logMessage ("Ajout non authorise d'un etat"); //$NON-NLS-1$
809 			Serveur.logServeur.logException ("GestionnaireConnexion", "initialisationGestionnaire", e); //$NON-NLS-1$//$NON-NLS-2$
810 		}
811 		catch (final ClassCastException e) {
812 			Serveur.logServeur.logMessage ("Ajout d'un etat qui existe deja"); //$NON-NLS-1$
813 			Serveur.logServeur.logException ("GestionnaireConnexion", "initialisationGestionnaire", e); //$NON-NLS-1$//$NON-NLS-2$
814 		}
815 	}
816 
817 	/**
818 	 * <p>
819 	 * Lister tout les canaux du serveur pour avoir leur nombre d'utilisateur et
820 	 * leur sujet.
821 	 * </p>
822 	 * 
823 	 * @param nomCanal
824 	 *            Nom du canal sur lequel on veux connaître les informations (si
825 	 *            le paramètre est vide tout les canaux seront choisi)
826 	 * @throws IOException
827 	 *             Un envoie à un client a échoué.
828 	 */
829 	public synchronized void lister (final String nomCanal) throws IOException {
830 		String reponse = ""; //$NON-NLS-1$
831 
832 		if (this.etats.contains (Etat.authentifie)) {
833 			try {
834 				reponse = "+OK_LISTER" + GestionnaireConnexion.CR + this.serveur.listerCanaux (nomCanal); //$NON-NLS-1$
835 			}
836 			catch (final CanalInexistantException e) {
837 				reponse = "-ERR_CANALINTROUVABLE " + nomCanal; //$NON-NLS-1$
838 			}
839 		}
840 		else {
841 			reponse = "-ERR_ETAT"; //$NON-NLS-1$
842 		}
843 		this.envoyer (reponse);
844 	}
845 
846 	/**
847 	 * <p>
848 	 * Liste les utilisateurs d'un canal.
849 	 * </p>
850 	 * 
851 	 * @param nom_canal
852 	 *            Nom du canal dont on veut connaître les membres.
853 	 * @throws IOException
854 	 *             Un envoie à un client a échoué.
855 	 */
856 	public synchronized void membre (final String nom_canal) throws IOException {
857 		String reponse = ""; //$NON-NLS-1$
858 
859 		if (this.etats.contains (Etat.authentifie)) {
860 			final int tmp = this.serveur.canalExistant (nom_canal);
861 
862 			if (tmp != -1) {
863 				reponse = "+OK_MEMBRE " + nom_canal + GestionnaireConnexion.CR + this.listeCanaux.get (nom_canal).listerMembre (); //$NON-NLS-1$
864 			}
865 			else {
866 				reponse = "-ERR_CANALINTROUVABLE " + nom_canal; //$NON-NLS-1$
867 			}
868 		}
869 		else {
870 			reponse = "-ERR_ETAT"; //$NON-NLS-1$
871 		}
872 		this.envoyer (reponse);
873 	}
874 
875 	/**
876 	 * <p>
877 	 * Envoyer un message sur un canal.
878 	 * </p>
879 	 * 
880 	 * @param nom_canal
881 	 *            Nom du canal sur lequel envoyer le message.
882 	 * @param message
883 	 *            Message à envoyer sur le canal.
884 	 * @throws IOException
885 	 *             Un envoie à un client a échoué.
886 	 */
887 	private synchronized void message (final String nom_canal, final String message) throws IOException {
888 		String reponse = ""; //$NON-NLS-1$
889 
890 		if (this.etats.contains (Etat.authentifie) && this.etats.contains (Etat.connexion_canal)) {
891 			if (this.serveur.canalExistant (nom_canal) != -1) {
892 				if (this.listeCanaux.containsKey (nom_canal)) {
893 					this.listeCanaux.get (nom_canal).notifier (Evenement.PARLE, this.client.getLogin (), message);
894 					reponse = "+OK_MESSAGE"; //$NON-NLS-1$
895 				}
896 				else {
897 					reponse = "-ERR_NONCONNECTE"; //$NON-NLS-1$
898 				}
899 			}
900 			else {
901 				reponse = "-ERR_CANALINTROUVABLE"; //$NON-NLS-1$
902 			}
903 			reponse += " " + nom_canal; //$NON-NLS-1$
904 		}
905 		else {
906 			reponse = "-ERR_ETAT"; //$NON-NLS-1$
907 		}
908 		this.envoyer (reponse);
909 	}
910 	
911 	/**
912 	 * <p>
913 	 * Connaître le message du jour
914 	 * </p>
915 	 * 
916 	 * @throws IOException
917 	 * 			Erreur d'entrée sortie.
918 	 */
919 	private synchronized void motd () throws IOException {
920 		String reponse = this.serveur.requeteMOTD ();
921 		
922 		if (reponse.compareTo ("") == 0) { //$NON-NLS-1$
923 			reponse = "-ERR_INTERNE"; //$NON-NLS-1$
924 		}
925 		else {
926 			reponse = "+OK_MOTD \"" + reponse + "\""; //$NON-NLS-1$ //$NON-NLS-2$
927 		}
928 		this.envoyer (reponse);
929 	}
930 	
931 	/**
932 	 * <p>
933 	 * Informations envoyer par le serveur afin de mettre au courant tout les
934 	 * utilisateurs d'un canal ce qui s'y passe dessus.
935 	 * </p>
936 	 * 
937 	 * @param nom_canal
938 	 *            Nom du canal sur lequel envoyer les informations.
939 	 * @param evenement
940 	 *            Evenement correspondant à l'information envoyé.
941 	 * @param login
942 	 *            Login de l'utilisateur originaire de l'information.
943 	 * @param message
944 	 *            Message à envoyer sur le canal.
945 	 * @throws IOException
946 	 *             Un envoie à un client a échoué.
947 	 */
948 	public void notifier (final String nom_canal, final Evenement evenement, final String login, final String message) throws IOException {
949 		String res = "NOTIFIER " + nom_canal + " " + evenement.toString (); //$NON-NLS-1$ //$NON-NLS-2$
950 
951 		switch (evenement) {
952 			case REJOINT:
953 			case PARTI:
954 			case EJECTE:
955 				res += " " + login; //$NON-NLS-1$
956 				break;
957 			case BANNI:
958 				res += " " + login; //$NON-NLS-1$
959 				break;
960 			case PARLE:
961 				res += " " + login + " \"" + message + "\""; //$NON-NLS-1$//$NON-NLS-2$ //$NON-NLS-3$
962 				break;
963 
964 			case SUJETCHANGE:
965 				res += " " + "\"" + message + "\""; //$NON-NLS-1$ //$NON-NLS-2$//$NON-NLS-3$
966 				break;
967 
968 			case SUPPRIME:
969 				break;
970 		}
971 		this.envoyer (res);
972 	}
973 
974 	/**
975 	 * <p>
976 	 * Quitter le serveur.
977 	 * </p>
978 	 * 
979 	 * @param msg
980 	 *            Message de départ (non obligatoire).
981 	 */
982 	public synchronized void quitter (final String msg) {
983 		// Départ des canaux auxquels on est connecté
984 		if (this.etats.contains (Etat.connexion_canal)) {
985 			for (final Entry<String, Canal> entry:this.listeCanaux.entrySet ()) {
986 				final Canal valeur = entry.getValue ();
987 
988 				try {
989 					valeur.notifier (Evenement.PARLE, this.client.getLogin (), msg);
990 					valeur.enleverGC (this);
991 				}
992 				catch (final NonConnecteException e) {
993 					Serveur.logCoDeco.logMessage (this.client.getLogin () + " n'est pas connecté au canal"); //$NON-NLS-1$
994 					Serveur.logCoDeco.logException ("GestionnaireException", "quitter", e); //$NON-NLS-1$ //$NON-NLS-2$
995 				}
996 				catch (final IOException e) {
997 					Serveur.logServeur.logMessage ("Erreur d'entrée sortie"); //$NON-NLS-1$
998 					Serveur.logServeur.logException ("GestionnaireException", "quitter", e); //$NON-NLS-1$ //$NON-NLS-2$
999 				}
1000 			}
1001 		}
1002 
1003 		// Suppression des connexions directes
1004 		if (this.etats.contains (Etat.connexion_directe)) {
1005 			for (int i = 0;i < this.listeNomAccepte.size ();i++) {
1006 				GestionnaireConnexion gc = new GestionnaireConnexion ();
1007 
1008 				try {
1009 					gc = this.serveur.connexion_directe (this.listeNomAccepte.get (i));
1010 
1011 					gc.listeNomAccepte.remove (this.client.getLogin ());
1012 					gc = null;
1013 				}
1014 				catch (final LoginIntrouvableException e) {
1015 					Serveur.logCoDeco.logMessage (this.client.getLogin () + " n'est pas connecté"); //$NON-NLS-1$
1016 					Serveur.logCoDeco.logException ("GestionnaireException", "quitter", e); //$NON-NLS-1$ //$NON-NLS-2$
1017 				}
1018 			}
1019 		}
1020 
1021 		// Deconnexion du serveur et remise à zero du GC
1022 		if (this.serveur != null) {
1023 			this.serveur.deconnexion (this.numeroGC);
1024 		}
1025 	}
1026 
1027 	/**
1028 	 * <p>
1029 	 * Quitter un canal.
1030 	 * </p>
1031 	 * 
1032 	 * @param nom_canal
1033 	 *            Nom du vanal qu'on veut quitter.
1034 	 * @throws IOException
1035 	 *             Un envoie à un client a échoué.
1036 	 */
1037 	private synchronized void quitterCanal (final String nom_canal) throws IOException {
1038 		String reponse = ""; //$NON-NLS-1$
1039 
1040 		if (this.etats.contains (Etat.authentifie) && this.etats.contains (Etat.connexion_canal)) {
1041 			final int tmp = this.serveur.canalExistant (nom_canal);
1042 
1043 			if (tmp != -1) {
1044 				if (!this.listeCanaux.containsKey (nom_canal)) {
1045 					reponse = "-ERR_NONCONNECTE " + nom_canal; //$NON-NLS-1$
1046 				}
1047 				else {
1048 					try {
1049 						this.listeCanaux.get (nom_canal).enleverGC (this);
1050 
1051 						reponse = "+OK_QUITTERCANAL " + nom_canal; //$NON-NLS-1$
1052 					}
1053 					catch (final NonConnecteException e) {
1054 						reponse = "-ERR_NONCONNECTE " + nom_canal; //$NON-NLS-1$
1055 					}
1056 					this.enleverCanal (nom_canal);
1057 					if (this.listeCanaux.isEmpty ()) {
1058 						this.etats.remove (Etat.connexion_canal);
1059 					}
1060 				}
1061 			}
1062 			else {
1063 				reponse = "-ERR_CANALINTROUVABLE " + nom_canal; //$NON-NLS-1$
1064 			}
1065 		}
1066 		else {
1067 			reponse = "-ERR_ETAT"; //$NON-NLS-1$
1068 		}
1069 		this.envoyer (reponse);
1070 	}
1071 
1072 	/**
1073 	 * <p>
1074 	 * Rejoindre un canal.
1075 	 * </p>
1076 	 * 
1077 	 * @param nom_canal
1078 	 *            Nom du canal que l'on veut rejoindre.
1079 	 * @throws IOException
1080 	 *             Un envoie à un client a échoué.
1081 	 */
1082 	private synchronized void rejoindre (final String nom_canal) throws IOException {
1083 		String reponse = ""; //$NON-NLS-1$
1084 
1085 		if (this.etats.contains (Etat.authentifie)) {
1086 			final int tmp = this.serveur.canalExistant (nom_canal);
1087 
1088 			if (tmp != -1) {
1089 				try {
1090 					this.listeCanaux.put (nom_canal, this.serveur.getListeCanaux ().get (tmp));
1091 					this.listeCanaux.get (nom_canal).ajouterGC (this);
1092 					if (!this.etats.contains (Etat.connexion_canal)) {
1093 						this.etats.add (Etat.connexion_canal);
1094 					}
1095 
1096 					reponse = "+OK_REJOINDRE " + nom_canal; //$NON-NLS-1$
1097 				}
1098 				catch (final DejaConnecteException e) {
1099 					reponse = "-ERR_DEJACONNECTE " + nom_canal; //$NON-NLS-1$
1100 				}
1101 			}
1102 			else {
1103 				reponse = "-ERR_CANALINTROUVABLE " + nom_canal; //$NON-NLS-1$
1104 			}
1105 		}
1106 		else {
1107 			reponse = "-ERR_ETAT"; //$NON-NLS-1$
1108 		}
1109 		this.envoyer (reponse);
1110 	}
1111 
1112 	/**
1113 	 * <p>
1114 	 * Méthode principal de lancement du thread.
1115 	 * </p>
1116 	 */
1117 	@Override
1118 	public void run () {
1119 		String message = ""; //$NON-NLS-1$
1120 		List<String> retour = Collections.synchronizedList (new ArrayList<String> ());
1121 
1122 		/*try {
1123 			this.envoyer (Serveur.MOTD);
1124 			this.sortie.flush ();
1125 		}
1126 		catch (final IOException e) {
1127 			Serveur.logServeur.logMessage ("Erreur d'E/S lors de l'utilisation du socket"); //$NON-NLS-1$
1128 			Serveur.logServeur.logException ("GestionnaireConnexion", "run", e); //$NON-NLS-1$ //$NON-NLS-2$
1129 		}*/
1130 		while (this.lance) {
1131 			boolean err_syntaxe = false;
1132 			String cmd = ""; //$NON-NLS-1$
1133 			int size = 0;
1134 
1135 			try {
1136 				message = this.entree.readLine ();
1137 				if (message != null) {
1138 					retour = this.analyseMessage (message);
1139 				}
1140 			}
1141 			catch (final IOException e1) {
1142 				if (this.lance) {
1143 					this.quitter ("déconnexion sauvage de " + this.client.getLogin ()); //$NON-NLS-1$
1144 				}
1145 				break;
1146 			}
1147 			catch (final CommandeIncorrecteException e) {
1148 				try {
1149 					this.envoyer ("-ERR_SYNTAXE"); //$NON-NLS-1$
1150 				}
1151 				catch (final IOException e1) {
1152 					Serveur.logServeur.logMessage ("Erreur d'entrée sortie"); //$NON-NLS-1$
1153 					Serveur.logServeur.logException ("GestionnaireConnexion", "run", e); //$NON-NLS-1$ //$NON-NLS-2$
1154 					break;
1155 				}
1156 				continue;
1157 			}
1158 			size = retour.size ();
1159 			if (size != 0) {
1160 				cmd = retour.get (0);
1161 			}
1162 			else {
1163 				break;
1164 			}
1165 
1166 			/* Commandes enregistrement de la connexion */
1167 			if (0 == cmd.compareToIgnoreCase ("IDENTIFIER")) { //$NON-NLS-1$
1168 				if (size == 3) {
1169 					try {
1170 						this.identifier (retour.get (1), retour.get (2));
1171 					}
1172 					catch (final IOException e) {
1173 						Serveur.logCoDeco.logMessage ("Déconnexion sauvage de " + this.client.getLogin ()); //$NON-NLS-1$
1174 						this.quitter ("déconnexion sauvage de " + this.client.getLogin ()); //$NON-NLS-1$
1175 						break;
1176 					}
1177 				}
1178 				else {
1179 					err_syntaxe = true;
1180 				}
1181 			}
1182 			else if (0 == cmd.compareToIgnoreCase ("QUITTER")) { //$NON-NLS-1$
1183 				if (size == 1) {
1184 					this.quitter (""); //$NON-NLS-1$
1185 					this.lance = false;
1186 				}
1187 				else if (size == 2) {
1188 					this.quitter (retour.get (1));
1189 					this.lance = false;
1190 				}
1191 				else {
1192 					err_syntaxe = true;
1193 				}
1194 			}
1195 			else if (0 == cmd.compareToIgnoreCase ("REJOINDRE")) { //$NON-NLS-1$		
1196 				if (size == 2) {
1197 					try {
1198 						this.rejoindre (retour.get (1));
1199 					}
1200 					catch (final IOException e) {
1201 						Serveur.logCoDeco.logMessage ("Déconnexion sauvage de " + this.client.getLogin ()); //$NON-NLS-1$
1202 						this.quitter ("déconnexion sauvage de " + this.client.getLogin ()); //$NON-NLS-1$
1203 						break;
1204 					}
1205 				}
1206 				else {
1207 					err_syntaxe = true;
1208 				}
1209 			}
1210 			else if (0 == cmd.compareToIgnoreCase ("MESSAGE")) { //$NON-NLS-1$
1211 				if (size == 3) {
1212 					try {
1213 						this.message (retour.get (1), retour.get (2));
1214 					}
1215 					catch (final IOException e) {
1216 						Serveur.logCoDeco.logMessage ("Déconnexion sauvage de " + this.client.getLogin ()); //$NON-NLS-1$
1217 						this.quitter ("déconnexion sauvage de " + this.client.getLogin ()); //$NON-NLS-1$
1218 						break;
1219 					}
1220 				}
1221 				else {
1222 					err_syntaxe = true;
1223 				}
1224 			}
1225 			else if (0 == cmd.compareToIgnoreCase ("QUITTERCANAL")) { //$NON-NLS-1$		
1226 				if (size == 2) {
1227 					try {
1228 						this.quitterCanal (retour.get (1));
1229 					}
1230 					catch (final IOException e) {
1231 						Serveur.logCoDeco.logMessage ("Déconnexion sauvage de " + this.client.getLogin ()); //$NON-NLS-1$
1232 						this.quitter ("déconnexion sauvage de " + this.client.getLogin ()); //$NON-NLS-1$
1233 						break;
1234 					}
1235 				}
1236 				else {
1237 					err_syntaxe = true;
1238 				}
1239 			}
1240 			else if (0 == cmd.compareToIgnoreCase ("MEMBRE")) { //$NON-NLS-1$		
1241 				if (size == 2) {
1242 					try {
1243 						this.membre (retour.get (1));
1244 					}
1245 					catch (final IOException e) {
1246 						Serveur.logCoDeco.logMessage ("Déconnexion sauvage de " + this.client.getLogin ()); //$NON-NLS-1$
1247 						this.quitter ("déconnexion sauvage de " + this.client.getLogin ()); //$NON-NLS-1$
1248 						break;
1249 					}
1250 				}
1251 				else {
1252 					err_syntaxe = true;
1253 				}
1254 			}
1255 
1256 			/* Commandes d'administration */
1257 			else if (0 == cmd.compareToIgnoreCase ("CNL_CREER")) { //$NON-NLS-1$
1258 				if (size == 3) {
1259 					try {
1260 						this.cnl_creer (retour.get (1), retour.get (2));
1261 					}
1262 					catch (final IOException e) {
1263 						Serveur.logCoDeco.logMessage ("Déconnexion sauvage de " + this.client.getLogin ()); //$NON-NLS-1$
1264 						this.quitter ("déconnexion sauvage de " + this.client.getLogin ()); //$NON-NLS-1$
1265 						break;
1266 					}
1267 				}
1268 				else {
1269 					err_syntaxe = true;
1270 				}
1271 			}
1272 			else if (0 == cmd.compareToIgnoreCase ("CNL_SUPPRIMER")) { //$NON-NLS-1$
1273 				if (size == 2) {
1274 					try {
1275 						this.cnl_supprimer (retour.get (1));
1276 					}
1277 					catch (final IOException e) {
1278 						Serveur.logCoDeco.logMessage ("Déconnexion sauvage de " + this.client.getLogin ()); //$NON-NLS-1$
1279 						this.quitter ("déconnexion sauvage de " + this.client.getLogin ()); //$NON-NLS-1$
1280 						break;
1281 					}
1282 				}
1283 				else {
1284 					err_syntaxe = true;
1285 				}
1286 			}
1287 			else if (0 == cmd.compareToIgnoreCase ("CNL_CHANGERSUJET")) { //$NON-NLS-1$
1288 				if (size == 3) {
1289 					try {
1290 						this.cnl_changerSujet (retour.get (1), retour.get (2));
1291 					}
1292 					catch (final IOException e) {
1293 						Serveur.logCoDeco.logMessage ("Déconnexion sauvage de " + this.client.getLogin ()); //$NON-NLS-1$
1294 						this.quitter ("déconnexion sauvage de " + this.client.getLogin ()); //$NON-NLS-1$
1295 						break;
1296 					}
1297 				}
1298 				else {
1299 					err_syntaxe = true;
1300 				}
1301 			}
1302 			else if (0 == cmd.compareToIgnoreCase ("UTL_EJECTER")) { //$NON-NLS-1$
1303 				if (size == 3) {
1304 					try {
1305 						this.utl_ejecter (retour.get (1), retour.get (2));
1306 					}
1307 					catch (final IOException e) {
1308 						Serveur.logCoDeco.logMessage ("Déconnexion sauvage de " + this.client.getLogin ()); //$NON-NLS-1$
1309 						this.quitter ("déconnexion sauvage de " + this.client.getLogin ()); //$NON-NLS-1$
1310 						break;
1311 					}
1312 				}
1313 				else {
1314 					err_syntaxe = true;
1315 				}
1316 			}
1317 			else if (0 == cmd.compareToIgnoreCase ("SRV_RELANCER")) { //$NON-NLS-1$
1318 				try {
1319 					if (size == 2) {
1320 						this.srv_relancer (retour.get (1));
1321 					}
1322 					else if (retour.size () == 1) {
1323 						this.srv_relancer (""); //$NON-NLS-1$
1324 					}
1325 					else {
1326 						err_syntaxe = true;
1327 					}
1328 				}
1329 				catch (final IOException e) {
1330 					Serveur.logCoDeco.logMessage ("Déconnexion sauvage de " + this.client.getLogin ()); //$NON-NLS-1$
1331 					this.quitter ("déconnexion sauvage de " + this.client.getLogin ()); //$NON-NLS-1$
1332 					break;
1333 				}
1334 			}
1335 			else if (0 == cmd.compareToIgnoreCase ("SRV_STOPPER")) { //$NON-NLS-1$
1336 				try {
1337 					if (size == 2) {
1338 						this.srv_stopper (retour.get (1));
1339 					}
1340 					else if (size == 1) {
1341 						this.srv_stopper (""); //$NON-NLS-1$
1342 					}
1343 					else {
1344 						err_syntaxe = true;
1345 					}
1346 				}
1347 				catch (final IOException e) {
1348 					Serveur.logCoDeco.logMessage ("Déconnexion sauvage de " + this.client.getLogin ()); //$NON-NLS-1$
1349 					this.quitter ("déconnexion sauvage de " + this.client.getLogin ()); //$NON-NLS-1$
1350 					break;
1351 				}
1352 			}
1353 			else if (0 == cmd.compareToIgnoreCase ("SRV_LISTER")) { //$NON-NLS-1$
1354 				if (size == 1) {
1355 					try {
1356 						this.srv_lister ();
1357 					}
1358 					catch (final IOException e) {
1359 						Serveur.logCoDeco.logMessage ("Déconnexion sauvage de " + this.client.getLogin ()); //$NON-NLS-1$
1360 						this.quitter ("déconnexion sauvage de " + this.client.getLogin ()); //$NON-NLS-1$
1361 						break;
1362 					}
1363 				}
1364 				else {
1365 					err_syntaxe = true;
1366 				}
1367 			}
1368 			else if (0 == cmd.compareToIgnoreCase ("UTL_BANNIR")) { //$NON-NLS-1$
1369 				if (size == 2) {
1370 					try {
1371 						this.utl_bannir (retour.get (1));
1372 					}
1373 					catch (final IOException e) {
1374 						Serveur.logCoDeco.logMessage ("Déconnexion sauvage de " + this.client.getLogin ()); //$NON-NLS-1$
1375 						this.quitter ("déconnexion sauvage de " + this.client.getLogin ()); //$NON-NLS-1$
1376 						break;
1377 					}
1378 				}
1379 				else {
1380 					err_syntaxe = true;
1381 				}
1382 			}
1383 			else if (0 == cmd.compareToIgnoreCase ("LISTER")) { //$NON-NLS-1$1 
1384 				try {
1385 					if (size == 2) {
1386 						this.lister (retour.get (1));
1387 					}
1388 					else if (size == 1) {
1389 						this.lister (""); //$NON-NLS-1$
1390 					}
1391 					else {
1392 						err_syntaxe = true;
1393 					}
1394 				}
1395 				catch (final IOException e) {
1396 					Serveur.logCoDeco.logMessage ("Déconnexion sauvage de " + this.client.getLogin ()); //$NON-NLS-1$
1397 					this.quitter ("déconnexion sauvage de " + this.client.getLogin ()); //$NON-NLS-1$
1398 					break;
1399 				}
1400 			}
1401 			else if (0 == cmd.compareToIgnoreCase ("INFOMEMBRE")) { //$NON-NLS-1$
1402 				if (retour.size () == 2) {
1403 					try {
1404 						this.infoMembre (retour.get (1));
1405 					}
1406 					catch (final IOException e) {
1407 						Serveur.logCoDeco.logMessage ("Déconnexion sauvage de " + this.client.getLogin ()); //$NON-NLS-1$
1408 						this.quitter ("déconnexion sauvage de " + this.client.getLogin ()); //$NON-NLS-1$
1409 						break;
1410 					}
1411 				}
1412 				else {
1413 					err_syntaxe = true;
1414 				}
1415 			}
1416 			else if (0 == cmd.compareToIgnoreCase ("MOTD")) { //$NON-NLS-1$
1417 				if (retour.size () == 1) {
1418 					try {
1419 						this.motd ();
1420 					}
1421 					catch (final IOException e) {
1422 						Serveur.logCoDeco.logMessage ("Déconnexion sauvage de " + this.client.getLogin ()); //$NON-NLS-1$
1423 						this.quitter ("déconnexion sauvage de " + this.client.getLogin ()); //$NON-NLS-1$
1424 						break;
1425 					}
1426 				}
1427 				else {
1428 					err_syntaxe = true;
1429 				}
1430 			}
1431 			else if (0 == cmd.compareToIgnoreCase ("CONNEXIONDIRECTE")) { //$NON-NLS-1$
1432 				if (retour.size () == 3) {
1433 					try {
1434 						this.connexionDirecte (retour.get (1), retour.get (2));
1435 					}
1436 					catch (final IOException e) {
1437 						Serveur.logCoDeco.logMessage ("Déconnexion sauvage de " + this.client.getLogin ()); //$NON-NLS-1$
1438 						this.quitter ("déconnexion sauvage de " + this.client.getLogin ()); //$NON-NLS-1$
1439 						break;
1440 					}
1441 				}
1442 				else {
1443 					err_syntaxe = true;
1444 				}
1445 			}
1446 			else if (0 == cmd.compareToIgnoreCase ("+OK_CONNEXIONDIRECTE")) { //$NON-NLS-1$
1447 				if (retour.size () == 4) {
1448 					try {
1449 						this.connexionDirecteAccepte (retour.get (1), retour.get (2), retour.get (3));
1450 					}
1451 					catch (final IOException e) {
1452 						Serveur.logCoDeco.logMessage ("Déconnexion sauvage de " + this.client.getLogin ()); //$NON-NLS-1$
1453 						this.quitter ("déconnexion sauvage de " + this.client.getLogin ()); //$NON-NLS-1$
1454 						break;
1455 					}
1456 				}
1457 				else {
1458 					err_syntaxe = true;
1459 				}
1460 			}
1461 			else if (0 == cmd.compareToIgnoreCase ("+KO_CONNEXIONDIRECTE")) { //$NON-NLS-1$
1462 				if (retour.size () == 2) {
1463 					try {
1464 						this.connexionDirecteRefuse (retour.get (1));
1465 					}
1466 					catch (final IOException e) {
1467 						Serveur.logCoDeco.logMessage ("Déconnexion sauvage de " + this.client.getLogin ()); //$NON-NLS-1$
1468 						this.quitter ("déconnexion sauvage de " + this.client.getLogin ()); //$NON-NLS-1$
1469 						break;
1470 					}
1471 				}
1472 				else {
1473 					err_syntaxe = true;
1474 				}
1475 			}
1476 			else {
1477 				try {
1478 					this.envoyer ("-ERR_CMDINCONNUE " + cmd); //$NON-NLS-1$
1479 				}
1480 				catch (final IOException e) {
1481 					Serveur.logCoDeco.logMessage ("Déconnexion sauvage de " + this.client.getLogin ()); //$NON-NLS-1$
1482 					this.quitter ("déconnexion sauvage de " + this.client.getLogin ()); //$NON-NLS-1$
1483 					break;
1484 				}
1485 			}
1486 			if (err_syntaxe) {
1487 				try {
1488 					this.envoyer ("-ERR_SYNTAXE"); //$NON-NLS-1$
1489 					this.sortie.flush ();
1490 				}
1491 				catch (final IOException e) {
1492 					Serveur.logCoDeco.logMessage ("Déconnexion sauvage de " + this.client.getLogin ()); //$NON-NLS-1$
1493 					this.quitter ("déconnexion sauvage de " + this.client.getLogin ()); //$NON-NLS-1$
1494 					break;
1495 				}
1496 			}
1497 		}
1498 	}
1499 
1500 	/**
1501 	 * <p>
1502 	 * Arrêter ou démarrer un thread.
1503 	 * </p>
1504 	 * 
1505 	 * @param lance1
1506 	 *            Boolean correspondant à l'état du thread.
1507 	 */
1508 	public void setLance (final boolean lance1) {
1509 		this.lance = lance1;
1510 	}
1511 
1512 	/**
1513 	 * <p>
1514 	 * Lister les clients du serveur.
1515 	 * </p>
1516 	 * 
1517 	 * @throws IOException
1518 	 *             Un envoie à un client a échoué.
1519 	 */
1520 	public synchronized void srv_lister () throws IOException {
1521 		String rep = ""; //$NON-NLS-1$
1522 
1523 		if (this.etats.contains (Etat.authentifie)) {
1524 			if (this.client.estAdministrateur ()) {
1525 				rep = "+OK_SRV_LISTER" + GestionnaireConnexion.CR + this.serveur.listerServeur (); //$NON-NLS-1$
1526 
1527 				this.envoyer (rep);
1528 			}
1529 			else {
1530 				this.envoyer ("-ERR_NONADMINISTRATEUR"); //$NON-NLS-1$
1531 			}
1532 		}
1533 		else {
1534 			this.envoyer ("-ERR_ETAT"); //$NON-NLS-1$
1535 		}
1536 	}
1537 
1538 	/**
1539 	 * <p>
1540 	 * Relancer le serveur.
1541 	 * </p>
1542 	 * 
1543 	 * @param s
1544 	 *            Message qui sera envoyé à tout les clients du serveur
1545 	 *            (optionnel).
1546 	 * @throws IOException
1547 	 *             Un envoie à un client a échoué.
1548 	 */
1549 	private synchronized void srv_relancer (final String s) throws IOException {
1550 		if (this.etats.contains (Etat.authentifie)) {
1551 			if (this.client.estAdministrateur ()) {
1552 				this.serveur.relancerServeur (s);
1553 			}
1554 			else {
1555 				this.envoyer ("-ERR_NONADMINISTRATEUR"); //$NON-NLS-1$
1556 			}
1557 		}
1558 		else {
1559 			this.envoyer ("-ERR_ETAT"); //$NON-NLS-1$
1560 		}
1561 	}
1562 
1563 	/**
1564 	 * <p>
1565 	 * Arrêt du serveur.
1566 	 * </p>
1567 	 * 
1568 	 * @param s
1569 	 *            Message qui sera envoyé à tout les clients du serveur
1570 	 *            (optionnel).
1571 	 * @throws IOException
1572 	 *             Un envoie à un client a échoué.
1573 	 */
1574 	private synchronized void srv_stopper (final String s) throws IOException {
1575 		if (this.etats.contains (Etat.authentifie)) {
1576 			if (this.client.estAdministrateur ()) {
1577 				this.serveur.stopperServeur (s);
1578 			}
1579 			else {
1580 				this.envoyer ("-ERR_NONADMINISTRATEUR"); //$NON-NLS-1$
1581 			}
1582 		}
1583 		else {
1584 			this.envoyer ("-ERR_ETAT"); //$NON-NLS-1$
1585 		}
1586 	}
1587 
1588 	/**
1589 	 * <p>
1590 	 * Message envoyé par le serveur pour une coupure de connexion. Lors d'un
1591 	 * relancement ou de l'arrêt.
1592 	 * </p>
1593 	 * 
1594 	 * @param message
1595 	 *            Message qui sera envoyer lors de la coupure de la connexion
1596 	 *            (optionnel).
1597 	 */
1598 	public void stopper (final String message) {
1599 		try {
1600 			if (message.equals ("")) { //$NON-NLS-1$
1601 				this.envoyer ("FINCONNEXION"); //$NON-NLS-1$
1602 			}
1603 			else {
1604 				this.envoyer ("FINCONNEXION " + message); //$NON-NLS-1$
1605 			}
1606 		}
1607 		catch (final IOException e) {
1608 			Serveur.logServeur.logMessage ("Erreur d'entrée sortie"); //$NON-NLS-1$
1609 			Serveur.logServeur.logException ("GestionnaireConnexion", "run", e); //$NON-NLS-1$ //$NON-NLS-2$
1610 		}
1611 		this.vider ();
1612 	}
1613 
1614 	/**
1615 	 * <p>
1616 	 * Bannir un utilisateur du serveur.
1617 	 * </p>
1618 	 * 
1619 	 * @param login
1620 	 *            Login de l'utilisateur à bannir.
1621 	 * @throws IOException
1622 	 *             Un envoie à un client a échoué.
1623 	 */
1624 	public synchronized void utl_bannir (final String login) throws IOException {
1625 		String reponse = ""; //$NON-NLS-1$
1626 
1627 		if (this.etats.contains (Etat.authentifie)) {
1628 			if (this.client.estAdministrateur ()) {
1629 				try {
1630 					this.serveur.bannirUtilisateur (login);
1631 
1632 					reponse = "+OK_UTL_BANNIR " + login; //$NON-NLS-1$
1633 				}
1634 				catch (final LoginIntrouvableException e1) {
1635 					reponse = "-ERR_LOGININTROUVABLE " + login; //$NON-NLS-1$
1636 				}
1637 				catch (NonConnecteException e) {
1638 					reponse = "-ERR_NONCONNECTE " + login; //$NON-NLS-1$
1639 				}
1640 			}
1641 			else {
1642 				reponse = "-ERR_NONADMINISTRATEUR"; //$NON-NLS-1$
1643 			}
1644 		}
1645 		else {
1646 			reponse = "-ERR_ETAT"; //$NON-NLS-1$
1647 		}
1648 		this.envoyer (reponse);
1649 	}
1650 
1651 	/**
1652 	 * <p>
1653 	 * Ejecter un utilisateur du canal.
1654 	 * </p>
1655 	 * 
1656 	 * @param login
1657 	 *            Login du client à éjecter.
1658 	 * @param nom_canal
1659 	 *            Nom du canal ou se trouve le client à éjecter.
1660 	 * @throws IOException
1661 	 *             Un envoie à un client a échoué.
1662 	 */
1663 	private synchronized void utl_ejecter (final String login, final String nom_canal) throws IOException {
1664 		String reponse = ""; //$NON-NLS-1$
1665 
1666 		if (this.etats.contains (Etat.authentifie)) {
1667 			if (this.client.estAdministrateur ()) {
1668 				try {
1669 					this.serveur.ejecterUtilisateur (login, nom_canal);
1670 
1671 					reponse = "+OK_UTL_EJECTER " + login + " " + nom_canal; //$NON-NLS-1$ //$NON-NLS-2$
1672 				}
1673 				catch (final CanalInexistantException e) {
1674 					reponse = "-ERR_CANALINTROUVABLE " + nom_canal; //$NON-NLS-1$
1675 				}
1676 				catch (final LoginIntrouvableException e1) {
1677 					reponse = "-ERR_LOGININTROUVABLE " + login; //$NON-NLS-1$
1678 				}
1679 				catch (final NonConnecteException e2) {
1680 					reponse = "-ERR_NONCONNECTE " + login + " " + nom_canal; //$NON-NLS-1$ //$NON-NLS-2$
1681 				}
1682 			}
1683 			else {
1684 				reponse = "-ERR_NONADMINISTRATEUR"; //$NON-NLS-1$
1685 			}
1686 		}
1687 		else {
1688 			reponse = "-ERR_ETAT"; //$NON-NLS-1$
1689 		}
1690 		this.envoyer (reponse);
1691 	}
1692 
1693 	/**
1694 	 * <p>
1695 	 * Vidage du gestionnaire de connexion dans l'optique d'une possible
1696 	 * réutilisation.
1697 	 * </p>
1698 	 */
1699 	public synchronized void vider () {
1700 		try {
1701 			this.sortie.close ();
1702 			this.entree.close ();
1703 			this.socket.close ();
1704 		}
1705 		catch (final IOException e) {
1706 			Serveur.logServeur.logMessage ("Erreur d'entrée sortie"); //$NON-NLS-1$
1707 			Serveur.logServeur.logException ("GestionnaireConnexion", "run", e); //$NON-NLS-1$ //$NON-NLS-2$
1708 		}
1709 
1710 		this.socket = null;
1711 		this.serveur = null;
1712 
1713 		this.client.vider ();
1714 		this.etats.clear ();
1715 		this.listeCanaux.clear ();
1716 
1717 		this.numeroGC = 0;
1718 		this.lance = false;
1719 		this.sortie = null;
1720 		this.entree = null;
1721 	}
1722 }