]> gitweb.pimeys.fr Git - bots/basile.git/blob - basile.py
Des messages HELP bien mieux organisés et tous présents.
[bots/basile.git] / basile.py
1 #!/usr/bin/python
2 # -*- coding:utf8 -*-
3
4 # Codé par 20-100 (commencé le 23/04/12)
5
6 # Un bot IRC qui, un jour, s'interfacera avec la Note Kfet 2015
7
8 import irclib
9 import ircbot
10 import threading
11 import random
12 import time
13 import socket, ssl, json
14 import pickle
15 import re
16 import os
17 from commands import getstatusoutput as ex
18
19 import sys
20 config_debug_stdout=True
21 if "--quiet" in sys.argv:
22 config_debug_stdout=False
23
24 config_irc_password="NK2015BasileB0t"
25 config_irc_pseudo="Basile"
26 config_chanlist=["#bot","#flood"]
27 config_stay_channels=["#bot","#flood"]
28 config_quiet_channels=[]
29 config_note_pseudo="Basile"
30 config_note_password="NK2015BasileB0tr4nd0omp4assword]6_+{#]78{"
31 config_logfile_template="basile.%s.log"
32 def get_config_logfile(serveur):
33 serveurs={"acoeur.crans.org":"acoeur","irc.crans.org":"crans"}
34 return config_logfile_template%(serveurs[serveur])
35 config_overops=["[20-100]","[20-100]_", "PEB"]
36 config_ops=["Nit"]
37 config_report_bugs_to=["[20-100]"]
38
39 # config "ce bot a été codé par 20-100, tu te rappelles ?"
40 config_manzana = ["[20-100]", "Petite-Peste"]
41 # config "mais PEB aussi est passé par là"
42 config_manzana_bis = ["PEB"]
43
44 # config "tu m'traites ?"
45 config_insultes=[u"conna(rd|sse)",u"pute",u"con(|ne)",u"enf(oiré|lure)",
46 u"sal(op(|e(|rie)|ard)|aud)",u"p(e|')tite bite",u"imbécile",u"idiot",u"stupid(|e)",u"débile",u"crétin",
47 u"pétasse",u"enculé",u"chagasse",u"cagole",u"abruti",u"ahuri",u"analphabète",u"andouille",
48 u"atardé",u"avorton",u"bachibouzouk",u"(balais|brosse) (de|à) chiotte(|s)",
49 u"batard",u"blaireau",u"bouffon",u"branque",u"bouseux",u"branleur",u"catin",u"chacal",
50 u"charogne",u"chiant(|e)",u"chieur",u"cochon",u"coprophage",u"couillon",u"crapule",u"crevard",
51 u"cruche",u"cuistre",u"ducon",u"décérébré",
52 u"emmerdeur",u"feignasse",u"fainéant",u"fourbe",u"freluquet",u"frigide",
53 u"garce",u"glandu",u"gogol",u"goujat",u"gourdasse",u"gredin",u"gringalet",u"grognasse",
54 u"naze",u"truie",u"iconoclaste",
55 u"peigne(-|)cul",u"ignare",u"illétré",u"lèche(|-)cul",u"malotru",u"motherfucker",u"nabot",u"nigaud",
56 u"nul",u"escroc",u"pouffiasse",u"pourriture",u"raclure",u"relou",u"sagouin",u"putain",
57 u"péripatéticienne"]
58 config_insultes_answers=[
59 u"Oh non ! Quelle insulte ! Je crois que je ne m'en relèverai jamais…\nEnfin presque.",
60 u"J'entends comme un vague murmure, vous disiez ?",
61 u"Je vais prendre ça pour un compliment.",
62 u"Vous savez, pour vous c'est peut-être une insulte, mais pour moi ce n'est qu'une suite de 0 et de 1…",
63 u"Permettez-moi de vous retourner le compliment.",
64 u"Votre indélicatesse vous sied à ravir.",
65 u"Parfois, je me demande pourquoi je fais encore ce métier…",
66 u"Le saviez-vous : l'invective ne déshonore que son auteur.",
67 u"Le saviez-vous : vous perdez plus de temps à m'insulter qu'à vous taire.",
68 u"Mais je ne vous permets pas ! Enfin, pas comme ça…"]
69
70 # config "à peine quelques kilos octets"
71 config_gros=[u"gros",u"énorme",u"lourd"]
72 config_thisfile= os.path.realpath( __file__ )
73 def get_filesize():
74 return ex("ls -s %s"%(config_thisfile))[1].split()[0]
75
76 # config spéciale-iota
77 config_buffer_fail_answers=[u"Pas de chance !",u"Révisez vos classiques !",
78 u"Encore un effort, je sais que vous pouvez le faire. ;)",
79 u"Where did you learn to type?"]
80
81 # config "jeu", d'ailleurs, j'ai perdu.
82 config_premier_groupe_terminaisons=u"(e|es|ons|ez|ent|er(|ai|as|a|ons|ez|ont)|(|er)(ais|ait|ions|iez|aient)|(a(i|s|)|â(mes|tes|t)|èrent)|ass(e(|s|nt)|i(ons|ez))|é(|s|e|es))"
83 config_regexp_etre=u"(être|suis|e(s|t)|so(mmes|nt)|êtes|(ét|ser)(ai(s|t|ent)|i(ons|ent)|)|ser(ai|as|a|ons|ez|ont)|so(i(s|t|ent)|y(ons|ez))|f(u(s|t|rent)|û(mes|tes|t))|fuss(e(|s|nt)|i(ons|ez))|étant)"
84 config_regexp_etre_avec_c=u"c'(e(s|st)|étai(t|ent))"
85 config_regexp_faire=u"fais"
86 config_perdu=[u"perd(|s|ons|ez|ent|r(e|ai|as|a|ons|ez|ont)|(|r)(ais|ait|ions|iez|aient))"
87 u"perd(i(s|t|rent)|î(mes|tes|t))", # oui, j'ai inclus qu'il perdît
88 u"perdiss(e(|s|nt)|i(ons|ez))",
89 u"perdu(|s|e|es)",u"perdant(|s|e|es)",u"perte(|s)",
90
91 u"(gagn|trouv)"+config_premier_groupe_terminaisons,u"gagnant(|s|e|es)",u"gain(|s)",
92
93 u"trouvant",u"trouvaille(|s)",
94
95 u"victoire(|s)",u"vaincu(|s|e|es)",
96 u"loose",u"lost",u"looser(|s)",u"win(|ner)(|s)",
97 u"jeu(|x)",u"game(|s)"]
98 config_time_between_perdu_trigger=3600*3 #temps moyen pour perdre en l'absence de trigger
99 config_time_between_perdu_trigger_delta = 30*60 #marge autorisée autour de ^^^
100 config_time_between_perdu=30*60 #temps pendant lequel on ne peut pas perdre
101
102 # config "tais-toi"
103 config_tag_triggers=[u"t(|a)g",u"ta gueule",u"la ferme",u"ferme( |-)la",u"tais-toi",u"chut",u"tu fais trop de bruit",u"tu parles trop"]
104 config_tag_actions=[u"se tait",u"se tient coi"]
105 config_tag_answers=[
106 u"Ç'aurait été avec plaisir, mais je ne crois pas que vous puissiez vous passer de mes services.",
107 u"Dès que cela sera utile.",
108 u"Une autre fois, peut-être.",
109 u"Si je me tais, qui vous rappellera combien vous me devez ?",
110 u"J'aurais aimé accéder à votre requête, mais après mûre réflexion, j'en ai perdu l'envie.",
111 u"Je ne ressens pas de besoin irrésistible de me taire, navré."]
112
113 # config ping
114 config_tesla_triggers=[u"t('|u )es là \?",u"\?",u"plop \?",u"plouf \?"]
115 config_tesla_answers=[
116 u"Oui, je suis là.",
117 u"J'écoute.",
118 u"En quoi puis-je me rendre utile ?",
119 u"On a besoin de moi ?"
120 ]
121 config_tesla_actions=[u"est là",u"attend des instructions",u"est toujours disponible"]
122
123 # config en cas de non-insulte
124 config_compliment_triggers=[u"gentil",u"cool",u"sympa",u"efficace"]
125 config_compliment_answers=[
126 u"Merci, c'est gentil de votre part. :)",
127 u"Permettez-moi de vous retourner le compliment, sans ironie cette fois.",
128 u"Je vous remercie.",
129 u"C'est trop d'honneur.",
130 u"Vous êtes bien aimable."
131 ]
132
133 # config merci
134 config_merci_triggers=[u"merci",u"remercie",u"thx",u"thank(|s)"]
135 config_merci_answers=[u"Mais de rien.",u"À votre service. ;)",u"Quand vous voulez. :)",
136 u"Tout le plaisir est pour moi."]
137
138 # config "ta mère"
139 config_tamere_triggers=[u"ta mère"]
140 config_tamere_answers=[u"Laissez donc ma mère en dehors de ça !",
141 u"Puis-je préciser que je n'ai pas de mère ? Seulement deux pères…",
142 u"""Un certain Max chantait "♩ J'ai vu ta mère sur chat rouleeeeeeette ♫", vous êtes de sa famille ?""",
143 u"""N'avait-on pas dit "pas les mamans" ?"""]
144
145 # config pour les actions désagréables à Basile
146 config_bad_action_triggers=[u"(frappe|cogne|tape)(| sur)",u"(démolit|dégomme|fouette|agresse|tabasse)",
147 u"(vomit|pisse|chie|crache) sur",u"slap(|s)"]
148 config_bad_action_answers=[
149 u"Je ne peux pas dire que j'apprécie, mais je l'ai sans doute bien mérité.",
150 u"{}: Pourquoi tant de violence en ce monde si doux ?",
151 u"""Si je n'étais pas aussi prude, je dirais "Mais euh…", cependant, je me contenterai de hausser un sourcil.""",
152 u"{}: J'aurais préféré que vous ne fassiez pas cela en public.",
153 u"{}: Entre nous, cela vous gratifie-t-il ?",
154 u"{}: Une telle relation entre nous deux n'est pas saine, revenons à quelque chose de plus conventionnel. :D",
155 u"J'ai la désagréable impression que {} cherche comment tuer le temps en ce moment…"
156 ]
157 config_bad_action_actions=[u"prend de la distance, par précaution…",u"esquive",u"est bon pour prendre une semaine de repos… virtuel !",u"n'aime pas servir de souffre douleur, mais n'a malheureusement pas le choix", u"s'en souviendra sans doute longtemps… de quoi parlait-on déjà ?"]
158
159 # config pour les actions agréables à Basile
160 config_good_action_triggers=[u"fait (:?des bisous|un c(?:â|a)lin|des c(?:â|a)lins) à",u"embrasse",u"c(?:â|a)line",u"caresse"]
161 config_good_action_answers=[u":D",u"{}: Moi aussi je vous aime. ♡",u"Tant de délicatesse ne saurait être ignorée !",u"Pour une fois que quelqu'un me considère à ma juste valeur…"]
162 config_good_action_actions=[u"ronronne",u"aimerait exprimer avec des mots simples le bonheur que {} lui procure !",u"éprouve une joie indescriptible",u"apprécie que des personnes comme {} soient sur IRC, sans quoi il n'y aurait sans doute jamais personne pour tenir compte de lui"]
163
164 # config bonjour/bonsoir/que fais-tu encore debout à cette heure, gros sale !
165 config_bonjour_triggers=[u"(s|)(a|'|)lu(t|)",u"hello",u"pl(o|i)p",u"pr(ou|ü)t",u"bonjour",u"bonsoir",u"coucou"]
166 config_bonjour_answers=[u"Bien le bonjour, {}.",u"Bonjour {}.",u"{}: bonjour.",u"{}: Quel beau temps aujourd'hui (arrêtez-moi si je me trompe) !",u"Meteo: Cachan"]
167 config_bonsoir_answers=[u"Bonsoir {} !",u"{}: bonsoir.",u"Quel beau te… euh… bonsoir !",u"{}: Je cherche désespérément une formule pour vous dire bonsoir, mais j'avoue que mon lexique est un peu… limité."]
168 config_night_answers=[u"{}: vous m'avez fait peur, je m'étais assoupi !", u"Debout à une heure pareille, {} ? Que vous arrive-t-il ?",u"Vous venez prendre la relève, {} ?"]
169 config_daytime = [7,18]
170 config_nighttime = [3, 6]
171
172 # config dodo
173 config_bonne_nuit_triggers=[u"bonne nuit",u"'?nite",u"'?nuit",u"'?night",u"good night",u"'?nenuit"]
174 config_bonne_nuit_answers=[u"{}: thanks, make sweet dreams tonight ! ;)",u"Bonne nuit {}.",u"À demain {}. :)",u"{}: si seulement j'avais le droit de dormir… enfin, bonne nuit !",u"{}: à vous aussi !"]
175
176 # config PEB est encore en train d'abuser de ses droits.
177 config_kick_answers=[u"Suis-je de trop ici ?",u"{}: je m'excuse pour ce bruit indu qui a stimulé votre colère",u"{} a le /kick facile, sans doute la fatigue.",u"{}: j'ai l'impression que vous n'allez pas bien aujourd'hui, vous vous en prenez à un robot !"]
178 config_kick_actions=[u"sera désormais exemplaire",u"prépare une lettre d'excuses à {}",u"essaiera de ne plus s'attirer les foudres de {}",u"croyait avoir tout bien fait… cruelle déception."]
179
180 # config on m'a demandé de mourir/partir
181 config_quit_messages=[u"Bien que cela me désole, je me vois dans l'obligation de vous abandonner."]
182 config_leave_messages=config_quit_messages
183
184 class NKError(Exception):
185 def __init__(self,msg):
186 Exception.__init__(self)
187 self.msg=msg
188 def __str__(self):
189 return str(self.msg)
190 def __unicode__(self):
191 return unicode(self.msg)
192
193 class NKRefused(NKError):
194 pass
195
196 class NKHelloFailed(NKError):
197 pass
198
199 class NKUnknownError(NKError):
200 pass
201
202 def log(serveur,channel,auteur=None,message=None):
203 f=open(get_config_logfile(serveur),"a")
204 if auteur==message==None:
205 # alors c'est que c'est pas un channel mais juste une ligne de log
206 chain="%s %s"%(time.strftime("%F %T"),channel)
207 else:
208 chain="%s [%s:%s] %s"%(time.strftime("%F %T"),channel,auteur,message)
209 f.write(chain+"\n")
210 if config_debug_stdout:
211 print chain
212 f.close()
213
214 def connect_NK():
215 sock=socket.socket()
216 try:
217 # On établit la connexion sur port 4242
218 sock.connect(("127.0.0.1",4242))
219 # On passe en SSL
220 sock=ssl.wrap_socket(sock,ca_certs='../keys/ca_.crt')
221 # On fait un hello
222 sock.write('hello "Basile"')
223 # On récupère la réponse du hello
224 out=sock.read()
225 out=json.loads(out)
226 except Exception as exc:
227 # Si on a foiré quelque part, c'est que le serveur est down
228 raise NKRefused(str(exc))
229 if out["retcode"]==0:
230 return sock
231 elif out["retcode"]==11:
232 raise NKHelloFailed(out["errmsg"])
233 else:
234 raise NKUnknownError(out["errmsg"])
235
236 def login_NK(username,password,typ="bdd"):
237 sock=connect_NK()
238 if typ=="special": # ça c'est pour Basile lui-même
239 masque='["note"]'
240 elif typ=="bdd":
241 masque='[["all"],["all"],false]'
242 try:
243 # Basile a un compte special user
244 commande='login [%s,%s,"%s",%s]'%(json.dumps(username),json.dumps(password),typ,masque)
245 sock.write(commande)
246 out=sock.read()
247 except Exception as exc:
248 # Si on a foiré quelque part, c'est que le serveur est down
249 raise NKRefused(str(exc))
250 # On vérifie ensuite que le login
251 return json.loads(out),sock
252
253
254 def is_something(chain,matches,avant=u".*(?:^| )",apres=u"(?:$|\.| |,|;).*",case_sensitive=False,debug=False):
255 if case_sensitive:
256 chain=unicode(chain,"utf8")
257 else:
258 chain=unicode(chain,"utf8").lower()
259 allmatches="("+"|".join(matches)+")"
260 reg=(avant+allmatches+apres).lower()
261 o=re.match(reg,chain)
262 return o
263
264 def is_insult(chain,debug=True):
265 return is_something(chain,config_insultes,avant=".*(?:^| |')")
266 def is_not_insult(chain):
267 chain=unicode(chain,"utf8")
268 insult_regexp=u"("+u"|".join(config_insultes)+u")"
269 middle_regexp=u"(une? (?:(?:putain|enfoiré) d(?:e |'))*|)(?:| super )(?: (?:gros|petit|grand|énorme) |)"
270 reg=".*pas %s%s.*"%(middle_regexp,insult_regexp)
271 if re.match(reg,chain):
272 return True
273 else:
274 return False
275 def is_compliment(chain,debug=True):
276 return is_something(chain,config_compliment_triggers,avant=".*(?:^| |')")
277 def is_perdu(chain):
278 return is_something(chain,config_perdu)
279 def is_tag(chain):
280 return is_something(chain,config_tag_triggers)
281 def is_gros(chain):
282 return is_something(chain,config_gros)
283 def is_tesla(chain):
284 return is_something(chain,config_tesla_triggers,avant=u"^",apres=u"$",debug=True)
285 def is_merci(chain):
286 return is_something(chain,config_merci_triggers)
287 def is_tamere(chain):
288 return is_something(chain,config_tamere_triggers)
289 def is_bad_action_trigger(chain,pseudo):
290 return is_something(chain,config_bad_action_triggers,avant=u"^",
291 apres="(?: [a-z]*ment)? %s($|\.| |,|;).*"%(pseudo))
292 def is_good_action_trigger(chain,pseudo):
293 return is_something(chain,config_good_action_triggers,avant=u"^",
294 apres="(?: [a-z]*ment)? %s($|\.| |,|;).*"%(pseudo))
295 def is_bonjour(chain):
296 return is_something(chain,config_bonjour_triggers,avant=u"^")
297 def is_bonne_nuit(chain):
298 return is_something(chain,config_bonne_nuit_triggers,avant=u"^")
299 def is_pan(chain):
300 return re.match(u"^(pan|bim|bang)( .*)?$",unicode(chain,"utf8").lower().strip())
301
302 def is_time(conf):
303 _,_,_,h,m,s,_,_,_=time.localtime()
304 return (conf[0],0,0)<(h,m,s)<(conf[1],0,0)
305 def is_day():
306 return is_time(config_daytime)
307 def is_night():
308 return is_time(config_nighttime)
309
310
311 class UnicodeBotError(Exception):
312 pass
313 def bot_unicode(chain):
314 try:
315 unicode(chain,"utf8")
316 except UnicodeDecodeError as exc:
317 raise UnicodeBotError
318
319 class Basile(ircbot.SingleServerIRCBot):
320 def __init__(self,serveur,debug=False):
321 temporary_pseudo=config_irc_pseudo+str(random.randrange(10000,100000))
322 ircbot.SingleServerIRCBot.__init__(self, [(serveur, 6667)],
323 temporary_pseudo,"Basile, le bot irc.[Codé par 20-100, fouettez-le]", 10)
324 self.debug=debug
325 self.serveur=serveur
326 self.overops=config_overops
327 self.ops=self.overops+config_ops
328 self.report_bugs_to=config_report_bugs_to
329 self.chanlist=config_chanlist
330 self.identities=pickle.load(open("identities.pickle","r"))
331 self.stay_channels=config_stay_channels
332 self.quiet_channels=config_quiet_channels
333 self.last_perdu=0
334
335
336 def new_connection_NK(self,serv,username,password,typ="bdd"):
337 try:
338 login_result,sock=login_NK(username,password,typ)
339 droits,retcode,errmsg=login_result["msg"],login_result["retcode"],login_result["errmsg"]
340 except NKRefused as exc:
341 for report in self.report_bugs_to:
342 serv.privmsg(report,"Le Serveur NK2015 est down.")
343 return (False,None)
344 except NKHelloFailed as exc:
345 for report in self.report_bugs_to:
346 serv.privmsg(report,
347 "La version du site utilisée n'est pas supportée par le serveur NK2015.")
348 return (False,None)
349 except NKUnknownError as exc:
350 erreurs=["Une fucking erreur inconnue s'est produite"]
351 erreurs+=str(exc).split("\n")
352 for report in self.report_bugs_to:
353 for err in erreurs:
354 serv.privmsg(report,err)
355 return (False,None)
356 except Exception as exc:
357 # Exception qui ne vient pas de la communication avec le serveur NK2015
358 log(self.serveur,"Erreur dans new_connection_NK\n"+str(exc))
359 return (False,None)
360 if retcode==0:
361 return (True,sock)
362 else:
363 return (False,None)
364
365 def give_me_my_pseudo(self,serv):
366 serv.privmsg("NickServ","RECOVER %s %s"%(config_irc_pseudo,config_irc_password))
367 serv.privmsg("NickServ","RELEASE %s %s"%(config_irc_pseudo,config_irc_password))
368 time.sleep(0.3)
369 serv.nick(config_irc_pseudo)
370
371 def on_welcome(self, serv, ev):
372 self.serv=serv # ça serv ira :)
373 self.give_me_my_pseudo(serv)
374 serv.privmsg("NickServ","identify %s"%(config_irc_password))
375 log(self.serveur,"Connected")
376 if self.debug:
377 self.chanlist=["#bot"]
378 for c in self.chanlist:
379 log(self.serveur,"JOIN %s"%(c))
380 serv.join(c)
381 # on ouvre la connexion note de Basile, special user
382 self.nk=self.new_connection_NK(serv,config_note_pseudo,config_note_password,"special")[1]
383 if self.nk==None:
384 for report in self.report_bugs_to:
385 serv.privmsg(report,"Connection to NK2015 failed, invalid password ?")
386
387 def lost(self,serv,channel,forced=False):
388 if self.last_perdu+config_time_between_perdu<time.time() or forced:
389 if not channel in self.quiet_channels or forced:
390 serv.privmsg(channel,"J'ai perdu !")
391 self.last_perdu=time.time()
392 delay=config_time_between_perdu_trigger
393 delta=config_time_between_perdu_trigger_delta
394 serv.execute_delayed(random.randrange(delay-delta,delay+delta),self.lost,(serv,channel))
395
396 def pourmoi(self, serv, message):
397 """renvoie (False,lemessage) ou (True, le message amputé de "pseudo: ")"""
398 pseudo=self.nick
399 size=len(pseudo)
400 if message[:size]==pseudo and len(message)>size and message[size]==":":
401 return (True,message[size+1:].lstrip(" "))
402 else:
403 return (False,message)
404
405 def on_privmsg(self, serv, ev):
406 message=ev.arguments()[0]
407 auteur = irclib.nm_to_n(ev.source())
408 try:
409 test=bot_unicode(message)
410 except UnicodeBotError:
411 serv.privmsg(auteur,
412 "Si je n'avais pas été créé avec la plus grande attention, votre encodage aurait eu raison de moi…")
413 return
414 message=message.split()
415 cmd=message[0].lower()
416 notunderstood=False
417 if cmd=="help":
418 helpdico={"help":["""HELP <commande>
419 Affiche de l'aide sur la commande""",None,None],
420 "identify": ["""IDENTIFY <username> <password>
421 Vérifie le mot de passe et me permet de savoir à l'avenir quel est votre pseudo note kfet.
422 Sans paramètre, je vous précise sous quel pseudo je vous connais.""",None,None],
423 "drop":["""DROP <password>
424 Vérifie le mot de passe et me fait d'oublier votre pseudo note kfet.""",None,None],
425 "solde": ["""SOLDE
426 Affiche votre solde, si je connais votre pseudo note kfet.""",
427 """SOLDE <pseudo>
428 Affiche le solde de la personne désignée (par son pseudo note).""",None],
429 "join": [None, """JOIN <channel>
430 Me fait rejoindre le channel""",None],
431 "leave": [None,"""LEAVE <channel>
432 Me fait quitter le channel (sauf s'il est dans ma stay_list).""",None],
433 "quiet": [None,"""QUIET <channel>
434 Me rend silencieux sur le channel.""",None],
435 "noquiet": [None,"""NOQUIET <channel>
436 Me rend la parole sur le channel.""",None],
437 "lost": [None,"""LOST <channel>
438 Me fait perdre sur le channel.""",None],
439 "say": [None,None,"""SAY <channel> <message>
440 Me fait parler sur le channel."""],
441 "do": [None,None,"""DO <channel> <action>
442 Me fait faitre une action (/me) sur le channel."""],
443 "stay": [None,None,"""STAY <channel>
444 Ajoute le channel à ma stay_list."""],
445 "nostay": [None,None,"""NOSTAY <channel>
446 Retire le channel de ma stay_list."""],
447 "ops": [None,None,"""OPS
448 Affiche la liste des ops."""],
449 "overops": [None,None,"""OVEROPS
450 Affiche la liste des overops."""],
451 "kick": [None,None,"""KICK <channel> <pseudo> [<raison>]
452 Kicke <pseudo> du channel (Il faut bien entendu que j'y sois op)."""],
453 "die": [None,None,"""DIE
454 Me déconnecte du serveur IRC."""]
455 }
456 helpmsg_default="Liste des commandes disponibles :\nHELP IDENTIFY DROP SOLDE"
457 helpmsg_ops=" JOIN LEAVE QUIET NOQUIET LOST"
458 helpmsg_overops=" SAY DO STAY NOSTAY OPS OVEROPS KICK DIE"
459 op,overop=auteur in self.ops, auteur in self.overops
460 if len(message)==1:
461 helpmsg=helpmsg_default
462 if op:
463 helpmsg+=helpmsg_ops
464 if overop:
465 helpmsg+=helpmsg_overops
466 else:
467 helpmsgs=helpdico.get(message[1].lower(),["Commande inconnue.",None,None])
468 helpmsg=helpmsgs[0]
469 if op and helpmsgs[1]:
470 if helpmsg:
471 helpmsg+="\n"+helpmsgs[1]
472 else:
473 helpmsg=helpmsgs[1]
474 if overop and helpmsgs[2]:
475 if helpmsg:
476 helpmsg+="\n"+helpmsgs[2]
477 else:
478 helpmsg=helpmsgs[2]
479 for ligne in helpmsg.split("\n"):
480 serv.privmsg(auteur,ligne)
481 elif cmd=="identify":
482 if len(message)==1:
483 if self.identities.has_key(auteur):
484 serv.privmsg(auteur,"Je vous connais sous le pseudo note %s."%(
485 self.identities[auteur].encode("utf8")))
486 else:
487 serv.privmsg(auteur,"Je ne connais pas votre pseudo note.")
488 elif len(message)>=3:
489 username,password=message[1],unicode(" ".join(message[2:]),"utf8")
490 success,_=self.new_connection_NK(serv,username,password)
491 if success:
492 log(self.serveur,"priv",auteur," ".join(message)+"[successful]")
493 serv.privmsg(auteur,"Identité enregistrée.")
494 self.identities[auteur]=username
495 pickle.dump(self.identities,open("identities.pickle","w"))
496 else:
497 log(self.serveur,"priv",auteur," ".join(message)+"[failed]")
498 serv.privmsg(auteur,"Mot de passe invalide. (ou serveur down)")
499 else:
500 serv.privmsg(auteur,u"Syntaxe : IDENTIFY [<username> <password>]")
501 elif cmd=="drop":
502 if len(message)>1:
503 if self.identities.has_key(auteur):
504 password=" ".join(message[1:])
505 success,_=self.new_connection_NK(serv,self.identities[auteur],password)
506 if success:
507 del self.identities[auteur]
508 log(self.serveur,"priv",auteur," ".join(message)+"[successful]")
509 pickle.dump(self.identities,open("identities.pickle","w"))
510 serv.privmsg(auteur,"Identité oubliée.")
511 else:
512 log(self.serveur,"priv",auteur," ".join(message)+"[failed]")
513 serv.privmsg(auteur,"Mot de passe invalide. (ou serveur down)")
514 else:
515 serv.privmsg(auteur,"Je ne connais pas ton pseudo note.")
516 else:
517 serv.privmsg(auteur,"Syntaxe : DROP <password>")
518 elif cmd=="join":
519 if auteur in self.ops:
520 if len(message)>1:
521 if message[1] in self.chanlist:
522 serv.privmsg(auteur,"Je suis déjà sur %s"%(message[1]))
523 else:
524 serv.join(message[1])
525 self.chanlist.append(message[1])
526 serv.privmsg(auteur,"Channels : "+" ".join(self.chanlist))
527 log(self.serveur,"priv",auteur," ".join(message))
528 else:
529 serv.privmsg(auteur,"Channels : "+" ".join(self.chanlist))
530 else:
531 notunderstood=True
532 elif cmd=="leave":
533 if auteur in self.ops and len(message)>1:
534 if message[1] in self.chanlist:
535 if not (message[1] in self.stay_channels) or auteur in self.overops:
536 self.quitter(message[1]," ".join(message[2:]))
537 self.chanlist.remove(message[1])
538 log(self.serveur,"priv",auteur," ".join(message)+"[successful]")
539 else:
540 serv.privmsg(auteur,"Non, je reste !")
541 log(self.serveur,"priv",auteur," ".join(message)+"[failed]")
542 else:
543 serv.privmsg(auteur,"Je ne suis pas sur %s"%(message[1]))
544 else:
545 notunderstood=True
546 elif cmd=="stay":
547 if auteur in self.overops:
548 if len(message)>1:
549 if message[1] in self.stay_channels:
550 log(self.serveur,"priv",auteur," ".join(message)+"[failed]")
551 serv.privmsg(auteur,"Je stay déjà sur %s."%(message[1]))
552 else:
553 log(self.serveur,"priv",auteur," ".join(message)+"[successful]")
554 self.stay_channels.append(message[1])
555 serv.privmsg(auteur,"Stay channels : "+" ".join(self.stay_channels))
556 else:
557 serv.privmsg(auteur,"Stay channels : "+" ".join(self.stay_channels))
558 else:
559 notunderstood=True
560 elif cmd=="nostay":
561 if auteur in self.overops:
562 if len(message)>1:
563 if message[1] in self.stay_channels:
564 log(self.serveur,"priv",auteur," ".join(message)+"[successful]")
565 self.stay_channels.remove(message[1])
566 serv.privmsg(auteur,"Stay channels : "+" ".join(self.stay_channels))
567 else:
568 log(self.serveur,"priv",auteur," ".join(message)+"[failed]")
569 serv.privmsg(auteur,"Je ne stay pas sur %s."%(message[1]))
570
571 else:
572 notunderstood=True
573 elif cmd=="die":
574 if auteur in self.overops:
575 log(self.serveur,"priv",auteur," ".join(message)+"[successful]")
576 self.mourir()
577 else:
578 notunderstood=True
579 elif cmd=="quiet":
580 if auteur in self.ops:
581 if len(message)>1:
582 if message[1] in self.quiet_channels:
583 serv.privmsg(auteur,"Je me la ferme déjà sur %s"%(message[1]))
584 log(self.serveur,"priv",auteur," ".join(message)+"[failed]")
585 else:
586 self.quiet_channels.append(message[1])
587 serv.privmsg(auteur,"Quiet channels : "+" ".join(self.quiet_channels))
588 log(self.serveur,"priv",auteur," ".join(message)+"[successful]")
589 else:
590 serv.privmsg(auteur,"Quiet channels : "+" ".join(self.quiet_channels))
591 else:
592 notunderstood=True
593 elif cmd=="noquiet":
594 if auteur in self.ops:
595 if len(message)>1:
596 if message[1] in self.quiet_channels:
597 self.quiet_channels.remove(message[1])
598 serv.privmsg(auteur,"Quiet channels : "+" ".join(self.quiet_channels))
599 log(self.serveur,"priv",auteur," ".join(message)+"[successful]")
600 else:
601 serv.privmsg(auteur,"Je ne me la ferme pas sur %s."%(message[1]))
602 log(self.serveur,"priv",auteur," ".join(message)+"[failed]")
603 else:
604 notunderstood=True
605 elif cmd=="say":
606 if auteur in self.overops and len(message)>2:
607 serv.privmsg(message[1]," ".join(message[2:]))
608 log(self.serveur,"priv",auteur," ".join(message))
609 elif len(message)<=2:
610 serv.privmsg(auteur,"Syntaxe : SAY <channel> <message>")
611 else:
612 notunderstood=True
613 elif cmd=="do":
614 if auteur in self.overops and len(message)>2:
615 serv.action(message[1]," ".join(message[2:]))
616 log(self.serveur,"priv",auteur," ".join(message))
617 elif len(message)<=2:
618 serv.privmsg(auteur,"Syntaxe : DO <channel> <action>")
619 else:
620 notunderstood=True
621 elif cmd=="kick":
622 if auteur in self.overops and len(message)>2:
623 serv.kick(message[1],message[2]," ".join(message[3:]))
624 log(self.serveur,"priv",auteur," ".join(message))
625 elif len(message)<=2:
626 serv.privmsg(auteur,"Syntaxe : KICK <channel> <pseudo> [<raison>]")
627 else:
628 notunderstood=True
629 elif cmd=="lost":
630 if auteur in self.ops and len(message)>1:
631 serv.privmsg(message[1],"J'ai perdu !")
632 log(self.serveur,"priv",auteur," ".join(message))
633 elif len(message)<=1:
634 serv.privmsg(auteur,"Syntaxe : LOST <channel>")
635 else:
636 notunderstood=True
637 elif cmd=="solde":
638 if len(message)==1:
639 if self.identities.has_key(auteur):
640 try:
641 self.nk.write('search ["x",["pseudo"],%s]'%(json.dumps(self.identities[auteur])))
642 ret=json.loads(self.nk.read())
643 solde=ret["msg"][0]["solde"]
644 pseudo=ret["msg"][0]["pseudo"]
645 except Exception as exc:
646 print exc
647 serv.privmsg(auteur,"failed")
648 log(self.serveur,"priv",auteur," ".join(message)+"[failed]")
649 return
650 serv.privmsg(auteur,"%s (%s)"%(float(solde)/100,pseudo.encode("utf8")))
651 log(self.serveur,"priv",auteur," ".join(message)+"[successful]")
652 else:
653 serv.privmsg(canal,"Je ne connais pas ton pseudo note.")
654 elif auteur in self.ops:
655 try:
656 self.nk.write('search ["x",["pseudo"],%s]'%(json.dumps(message[1])))
657 ret=json.loads(self.nk.read())
658 solde=ret["msg"][0]["solde"]
659 pseudo=ret["msg"][0]["pseudo"]
660 except Exception as exc:
661 serv.privmsg(auteur,"failed")
662 log(self.serveur,"priv",auteur," ".join(message)+"[failed]")
663 return
664 serv.privmsg(auteur,"%s (%s)"%(float(solde)/100,pseudo.encode("utf8")))
665 elif cmd=="ops":
666 if auteur in self.overops:
667 serv.privmsg(auteur," ".join(self.ops))
668 else:
669 notunderstood=True
670 elif cmd=="overops":
671 if auteur in self.overops:
672 serv.privmsg(auteur," ".join(self.overops))
673 else:
674 notunderstood=True
675 else:
676 notunderstood=True
677 if notunderstood:
678 serv.privmsg(auteur,"Je n'ai pas compris. Essayez HELP…")
679
680 def on_pubmsg(self, serv, ev):
681 auteur = irclib.nm_to_n(ev.source())
682 canal = ev.target()
683 message = ev.arguments()[0]
684 try:
685 test=bot_unicode(message)
686 except UnicodeBotError:
687 if not canal in self.quiet_channels:
688 serv.privmsg(canal,
689 "%s: Si je n'avais pas été créé avec la plus grande attention, votre encodage aurait eu raison de moi…"%(auteur))
690 return
691 pour_moi,message=self.pourmoi(serv,message)
692 if pour_moi and message.split()!=[]:
693 cmd=message.split()[0].lower()
694 try:
695 args=" ".join(message.split()[1:])
696 except:
697 args=""
698 if cmd in ["meurs","die","crève"]:
699 if auteur in self.overops:
700 log(self.serveur,canal,auteur,message+"[successful]")
701 self.mourir()
702 else:
703 serv.privmsg(canal,"%s: mourrez vous-même !"%(auteur))
704 log(self.serveur,canal,auteur,message+"[failed]")
705
706 elif cmd in ["part","leave","dégage","va-t-en","tut'tiresailleurs,c'estmesgalets"]:
707 if auteur in self.ops and (not (canal in self.stay_channels)
708 or auteur in self.overops):
709 self.quitter(canal)
710 log(self.serveur,canal,auteur,message+"[successful]")
711 if canal in self.chanlist:
712 self.chanlist.remove(canal)
713 else:
714 serv.privmsg(canal,"%s: Navré, mais je me vois contraint de refuser, je ne peux pas céder aux exigences du premier venu."%(auteur))
715 log(self.serveur,canal,auteur,message+"[failed]")
716
717 elif cmd in ["reconnect"]:
718 if auteur in self.ops:
719 try:
720 self.nk=self.new_connection_NK(serv,config_note_pseudo,
721 config_note_password,"special")[1]
722 except Exception as exc:
723 self.nk=None
724 log(self.serveur,"""Erreur dans on_pubmsg/"cmd in ["reconnect"]\n"""+str(exc))
725 if self.nk!=None:
726 serv.privmsg(canal,"%s: done"%(auteur))
727 log(self.serveur,canal,auteur,message+"[successful]")
728 else:
729 serv.privmsg(canal,"%s: failed"%(auteur))
730 log(self.serveur,canal,auteur,message+"[failed]")
731 for report in self.report_bugs_to:
732 serv.privmsg(report,"Connection to NK2015 failed, invalid password ?")
733 else:
734 serv.privmsg(canal,"%s: crève !"%(auteur))
735 log(self.serveur,canal,auteur,message+"[failed]")
736
737 elif cmd in ["deviens","pseudo"]:
738 if auteur in self.ops:
739 become=args
740 serv.nick(become)
741 log(self.serveur,canal,auteur,message+"[successful]")
742
743 if cmd in ["meur", "meurt","meurre","meurres"] and not canal in self.quiet_channels:
744 serv.privmsg(canal,'%s: Mourir, impératif, 2ème personne du singulier : "meurs" (de rien)'%(auteur))
745 elif cmd in ["ping"] and not canal in self.quiet_channels:
746 serv.privmsg(canal,"%s: pong"%(auteur))
747
748 elif cmd in ["solde","!solde"]:
749 if self.identities.has_key(auteur):
750 pseudo=self.identities[auteur]
751 try:
752 self.nk.write('search ["x",["pseudo"],%s]'%(json.dumps(pseudo)))
753 ret=json.loads(self.nk.read())
754 solde=ret["msg"][0]["solde"]
755 pseudo=ret["msg"][0]["pseudo"]
756 except Exception as exc:
757 serv.privmsg(canal,"%s: failed"%(auteur))
758 log(self.serveur,canal,auteur,message+"[failed]")
759 else:
760 serv.privmsg(canal,"%s: %s (%s)"%(auteur,float(solde)/100,pseudo.encode("utf8")))
761 log(self.serveur,canal,auteur,message+"[successful]")
762 else:
763 serv.privmsg(canal,"%s: Je ne connais pas votre pseudo note."%(auteur))
764 log(self.serveur,canal,auteur,message+"[unknown]")
765 elif (re.match("!?(pain au chocolat|chocolatine)",message.lower())
766 and not canal in self.quiet_channels):
767 serv.action(canal,"sert un pain au chocolat à %s"%(auteur))
768 elif re.match("!?manzana",message.lower()) and not canal in self.quiet_channels:
769 if auteur in config_manzana:
770 serv.action(canal,"sert une bouteille de manzana à %s"%(auteur))
771 elif auteur in config_manzana_bis:
772 serv.action(canal,"sert un grand verre de jus de pomme à %s : tout le monde sait qu'il ne boit pas."%(auteur))
773 else:
774 serv.action(canal,"sert un verre de manzana à %s"%(auteur))
775 if is_insult(message) and not canal in self.quiet_channels:
776 if is_not_insult(message):
777 answer=random.choice(config_compliment_answers)
778 for ligne in answer.split("\n"):
779 serv.privmsg(canal,"%s: %s"%(auteur,ligne.encode("utf8")))
780 else:
781 answer=random.choice(config_insultes_answers)
782 for ligne in answer.split("\n"):
783 serv.privmsg(canal,"%s: %s"%(auteur,ligne.encode("utf8")))
784 elif is_compliment(message) and not canal in self.quiet_channels:
785 answer=random.choice(config_compliment_answers)
786 for ligne in answer.split("\n"):
787 serv.privmsg(canal,"%s: %s"%(auteur,ligne.encode("utf8")))
788 gros_match=is_gros(message)
789 if gros_match and not canal in self.quiet_channels:
790 taille=get_filesize()
791 answer=u"Mais non, je ne suis pas %s, %sKo tout au plus…"%(gros_match.groups()[0],taille)
792 serv.privmsg(canal,"%s: %s"%(auteur,answer.encode("utf8")))
793 if is_tesla(message) and not canal in self.quiet_channels:
794 l1,l2=config_tesla_answers,config_tesla_actions
795 n1,n2=len(l1),len(l2)
796 i=random.randrange(n1+n2)
797 if i>=n1:
798 serv.action(canal,l2[i-n1].encode("utf8"))
799 else:
800 serv.privmsg(canal,"%s: %s"%(auteur,l1[i].encode("utf8")))
801 if is_tamere(message) and not canal in self.quiet_channels:
802 answer=random.choice(config_tamere_answers)
803 for ligne in answer.split("\n"):
804 serv.privmsg(canal,"%s: %s"%(auteur,ligne.encode("utf8")))
805 if is_tag(message) and not canal in self.quiet_channels:
806 if auteur in self.ops:
807 action=random.choice(config_tag_actions)
808 serv.action(canal,action.encode("utf8"))
809 self.quiet_channels.append(canal)
810 else:
811 answer=random.choice(config_tag_answers)
812 for ligne in answer.split("\n"):
813 serv.privmsg(canal,"%s: %s"%(auteur,ligne.encode("utf8")))
814 if is_merci(message):
815 answer=random.choice(config_merci_answers)
816 for ligne in answer.split("\n"):
817 serv.privmsg(canal,"%s: %s"%(auteur,ligne.encode("utf8")))
818 out=re.match(ur"^([A-Z[]|\\|[0-9]+|(¹|²|³|⁴|⁵|⁶|⁷|⁸|⁹|⁰)+)(?:| \?| !)$",
819 unicode(message.upper(),"utf8"))
820 if re.match("ma bite dans ton oreille",message) and not canal in self.quiet_channels:
821 serv.privmsg(canal,"%s: Seul un olasd peut imiter un olasd dans un de ses grands jours !"%(auteur))
822 if out and not canal in self.quiet_channels:
823 out=out.groups()[0]
824 try:
825 out=int(out)
826 serv.privmsg(canal,"%s: %s !"%(auteur,out+1))
827 if out==2147483647:
828 serv.privmsg(canal,"%s: Ciel, un maxint ! Heureusement que je suis en python…"%(auteur))
829 return
830 if out+1>1000 and random.randrange(4)==0:
831 serv.privmsg(canal,"%s: Vous savez, moi et les chiffres…"%(auteur))
832 return
833 except Exception as exc:
834 pass
835 if re.match("[A-Y]",out):
836 alphabet="ABCDEFGHIJKLMNOPQRSTUVWXYZ"
837 serv.privmsg(canal,"%s: %s !"%(auteur,alphabet[alphabet.index(out)+1]))
838 elif out=="Z":
839 serv.privmsg(canal,"%s: Je ne vous remercie pas, j'ai l'air idiot ainsi… [ ?"%(auteur))
840 elif out in "[\\":
841 serv.privmsg(canal,"%s: Nous devrions nous en tenir là, ça va finir par poser des problèmes…"%(auteur))
842 elif re.match(ur"(¹|²|³|⁴|⁵|⁶|⁷|⁸|⁹|⁰)+",out):
843 def translate(mess):
844 return "".join([{u"⁰¹²³⁴⁵⁶⁷⁸⁹0123456789"[i]:u"0123456789⁰¹²³⁴⁵⁶⁷⁸⁹"[i]
845 for i in range(20)}[j]
846 for j in mess])
847 out=int(translate(out))
848 serv.privmsg(canal,"%s: %s !"%(auteur,translate(str(out+1)).encode("utf8")))
849 if is_bonjour(message) and not canal in self.quiet_channels:
850 if is_night():
851 answer=random.choice(config_night_answers)
852 elif is_day():
853 answer=random.choice(config_bonjour_answers)
854 else:
855 answer=random.choice(config_bonsoir_answers)
856 serv.privmsg(canal,answer.format(auteur).encode("utf8"))
857 if is_bonne_nuit(message) and not canal in self.quiet_channels:
858 answer=random.choice(config_bonne_nuit_answers)
859 serv.privmsg(canal,answer.format(auteur).encode("utf8"))
860 if is_pan(message) and not canal in self.quiet_channels:
861 serv.privmsg(canal,"%s: ce n'est pas sur moi qu'il faut tirer, même si je sais que j'attire l'œil !"%(auteur))
862 else:
863 if message in ["!pain au chocolat","!chocolatine"] and not canal in self.quiet_channels:
864 serv.action(canal,"sert un pain au chocolat à %s"%(auteur))
865 if message in ["!manzana"] and not canal in self.quiet_channels:
866 if auteur in config_manzana:
867 serv.action(canal,"sert une bouteille de manzana à %s"%(auteur))
868 elif auteur in config_manzana_bis:
869 serv.action(canal,"sert un grand verre de jus de pomme à %s : tout le monde sait qu'il ne boit pas."%(auteur))
870 else:
871 serv.action(canal,"sert un verre de manzana à %s"%(auteur))
872 if re.match(u'^ *(.|§|!|/|/|:|)(w|b) [0-9]+$',message.decode("utf8")) and not canal in self.quiet_channels:
873 failanswers=config_buffer_fail_answers
874 answer=random.choice(failanswers)
875 serv.privmsg(canal,("%s: %s"%(auteur,answer)).encode("utf8"))
876 if not canal in self.quiet_channels:
877 mypseudo=self.nick
878 if re.match((u"^("+u"|".join(config_bonjour_triggers)
879 +u")( {}| all| tout le monde|(|à) tous)(\.|( |)!|)$"
880 ).format(mypseudo).lower(), message.strip().lower()):
881 answer=random.choice(config_bonjour_answers)
882 serv.privmsg(canal,answer.format(auteur).encode("utf8"))
883 if (is_perdu(message) and not canal in self.quiet_channels):
884 # proba de perdre sur trigger :
885 # avant 30min (enfin, config) : 0
886 # ensuite, +25%/30min, linéairement
887 deltat=time.time()-self.last_perdu
888 barre=(deltat-config_time_between_perdu)/(2*3600.0)
889 if random.uniform(0,1)<barre:
890 serv.privmsg(canal,"%s: J'ai perdu !"%(auteur))
891 self.last_perdu=time.time()
892
893 def on_action(self, serv, ev):
894 action = ev.arguments()[0]
895 auteur = irclib.nm_to_n(ev.source())
896 channel = ev.target()
897 try:
898 test=bot_unicode(action)
899 except UnicodeBotError:
900 serv.privmsg(channel,
901 "%s: Si je n'avais pas été créé avec la plus grande attention, votre encodage m'aurait déjà tué…"%(auteur))
902 return
903 mypseudo=self.nick
904
905 if is_bad_action_trigger(action,mypseudo) and not channel in self.quiet_channels:
906 l1,l2=config_bad_action_answers,config_bad_action_actions
907 n1,n2=len(l1),len(l2)
908 i=random.randrange(n1+n2)
909 if i>=n1:
910 serv.action(channel,l2[i-n1].format(auteur).encode("utf8"))
911 else:
912 serv.privmsg(channel,l1[i].format(auteur).format(auteur).encode("utf8"))
913 if is_good_action_trigger(action,mypseudo) and not channel in self.quiet_channels:
914 l1,l2=config_good_action_answers,config_good_action_actions
915 n1,n2=len(l1),len(l2)
916 i=random.randrange(n1+n2)
917 if i>=n1:
918 serv.action(channel,l2[i-n1].format(auteur).format(auteur).encode("utf8"))
919 else:
920 serv.privmsg(channel,l1[i].format(auteur).format(auteur).encode("utf8"))
921
922 def on_kick(self,serv,ev):
923 auteur = irclib.nm_to_n(ev.source())
924 channel = ev.target()
925 victime = ev.arguments()[0]
926 raison = ev.arguments()[1]
927 if victime==self.nick:
928 log(self.serveur,"%s kické par %s (raison : %s)" %(victime,auteur,raison))
929 time.sleep(2)
930 serv.join(channel)
931 l1,l2=config_kick_answers,config_kick_actions
932 n1,n2=len(l1),len(l2)
933 i=random.randrange(n1+n2)
934 if i>=n1:
935 serv.action(channel,l2[i-n1].format(auteur).encode("utf8"))
936 else:
937 serv.privmsg(channel,l1[i].format(auteur).encode("utf8"))
938
939 def quitter(self,chan,leave_message=None):
940 if leave_message==None:
941 leave_message=random.choice(config_leave_messages)
942 self.serv.part(chan,message=leave_message.encode("utf8"))
943
944 def mourir(self):
945 quit_message=random.choice(config_quit_messages)
946 self.die(msg=quit_message.encode("utf8"))
947
948 def _getnick(self):
949 return self.serv.get_nickname()
950 nick=property(_getnick)
951
952
953 if __name__=="__main__":
954 import sys
955 if len(sys.argv)==1:
956 print "Usage : basile.py <serveur> [--debug]"
957 exit(1)
958 serveur=sys.argv[1]
959 if "debug" in sys.argv or "--debug" in sys.argv:
960 debug=True
961 else:
962 debug=False
963 serveurs={"a♡":"acoeur.crans.org","acoeur":"acoeur.crans.org","acoeur.crans.org":"acoeur.crans.org",
964 "irc":"irc.crans.org","crans":"irc.crans.org","irc.crans.org":"irc.crans.org"}
965 try:
966 serveur=serveurs[serveur]
967 except KeyError:
968 print "Server Unknown : %s"%(serveur)
969 exit(404)
970 basile=Basile(serveur,debug)
971 basile.start()