unefede.pl 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321
  1. #!/bin/env perl
  2. # Copyright (c) 2014, 2015 Daniel Jakots <vigdis@chown.me>
  3. # Permission to use, copy, modify, and distribute this software for any
  4. # purpose with or without fee is hereby granted, provided that the above
  5. # copyright notice and this permission notice appear in all copies.
  6. #
  7. # Permission to use, copy, modify, and distribute this software for any
  8. # purpose with or without fee is hereby granted, provided that the above
  9. # copyright notice and this permission notice appear in all copies.
  10. #
  11. # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
  12. # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
  13. # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
  14. # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  15. # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
  16. # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  17. # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  18. use warnings;
  19. use strict;
  20. ######################################################################
  21. # this package was created only for checking modified files. If a #
  22. # file was modified, append timestamp will be updated, you need to #
  23. # have write access to checked file! #
  24. ######################################################################
  25. { package check;
  26. use strict;
  27. use warnings;
  28. use File::stat;
  29. use Time::localtime;
  30. use POSIX qw(strftime);
  31. sub fichier {
  32. my $file = shift();
  33. my $time;
  34. $time = shift() or $time = 10;
  35. # if checked file doesn't exist, return 0
  36. unless (-f $file) {
  37. return(0);
  38. }
  39. # init all local variables
  40. my $ltime = strftime("%s", @{ localtime() });
  41. my $atime = strftime("%s", @{ localtime(stat($file)->atime) });
  42. my $mtime = strftime("%s", @{ localtime(stat($file)->mtime) });
  43. my $ntime = $mtime-($time+2);
  44. # we check if localtime minus modified time is less than configured
  45. # time. If it's true, we set a new append/modified time via utime().
  46. if (($ltime-$mtime) <= $time) {
  47. utime($ntime, $ntime, $file);
  48. return(1);
  49. }
  50. else {
  51. return(0);
  52. }
  53. }
  54. }
  55. package MyBot;
  56. use base qw( Bot::BasicBot );
  57. binmode STDOUT, ":utf8";
  58. use utf8;
  59. # le repectoire des données du bot aka autoconf
  60. my $bot_dir = `pwd`; chomp $bot_dir ; $bot_dir .= "/";
  61. my $wrk_dir = "wrk-dir/";
  62. my $dir = $bot_dir.$wrk_dir;
  63. # symbol auquel le bot répond
  64. my $symbol = "+";
  65. # dictionnaire contenant les regex permettants de trouver les FAI
  66. my %regex = (
  67. "apinnet" => "(ap[in]|Poitou|Charente|Rochelle|(Deux[- ])?S[èe]vres?|Vienne|Angoul[eêè]me|Niort|Poitiers)",
  68. "aquilenet" => "(aq(ui|n)|Bord(o|e?au)|Landes|Gironde)",
  69. "arn" => "(a(lsace|rn)|Stras|Colma)",
  70. "auvernet" => "(Auver|Puy[- ](de[- ])D[oô]me|avn)",
  71. "cafai" => "(cafai|champagne|ardenn?e)",
  72. "faimaison" => "(fma|fail?m|Nantes|Loire[- ]Atlantique)",
  73. "fdn" => "f(rench|dn)",
  74. "franciliens" => "b(f(ranc|cn)|idf|Paris)",
  75. "grifon" => "(grif|rennes|[îi]l?le[- ](et[- ])?vilaine)",
  76. "ilico" => "(ilc|ill?[iy][ck])|(Corr?[éêèe][sz])",
  77. "illyse" => "(ill?y|ill?i[sz]|lyon|rh[ôo]ne|loire|((st|saint)[- ]etienn?e))",
  78. "iloth" => "(ilo|mont?pel|h[ée]rault)",
  79. "ldn" => "(l(or|dn)|Nancy|Metz|Moselle|Meuse|Meurthe|Vosges)",
  80. "ndn" => "(n(ice|dn)|Antibes|Cannes|Valbonne|Alpes[- ]Maritimes)",
  81. "netopi" => "(netopi|Seine[- ](et[- ])?Marne)",
  82. "pclight" => "(yonne|beon|cheny|pc[- ]?l)",
  83. "rezine" => "(r[eé]z|Isère|Grenoble)",
  84. "rhizome" => "(rh?[iy][sz]om|Oise|Compi[eéêè]gne)",
  85. "sames" => "sam|(Pyrénées[- ]Atlantiques)",
  86. "sdn" => "(s(all|dn)|Savoie|Haute[- ]Savoie)",
  87. "teleragno" => "(mars|telerag|telegrano)",
  88. "tetaneutral" => "(t(eta|tn|nn)|Toulouse|Comminges|(Haute[- ]Garon?ne))",
  89. "ail-network" => "a(il|utan)",
  90. "chaul-hertz" => "(c(haul|hz)|hertz|tarn)",
  91. "igwan" => "(ig[wn]|sbg|saint[- ]barth)",
  92. "neutrinet" => "(neutri|n[tre]n|belgique)",
  93. "ffdn" => "f(ede|fdn|rance|édé)",
  94. "tdn" => "(t(dn|ouraine)|centre|rouvr)",
  95. );
  96. # Lis le fichier contenant les infos d'un FAI
  97. sub info {
  98. my $fai = shift @_;
  99. my $filename = $dir.$fai.".info";
  100. if (-e $filename)
  101. {
  102. my $fh;
  103. open ($fh, '<', $filename) or die "Impossible d'ouvrir le fichier $filename en lecture";
  104. while (my $line = <$fh>)
  105. {
  106. return $line;
  107. }
  108. close $fh;
  109. }
  110. else
  111. {
  112. return "pas d'information pour ". $fai ."\n";
  113. }
  114. }
  115. # Lis le fichier contenant les nombres adh/abo d'un FAI
  116. sub adh {
  117. my $fai = shift @_;
  118. my $filename = $dir.$fai.".adh";
  119. if (-e $filename)
  120. {
  121. my $fh;
  122. open ($fh, '<', $filename) or die "Impossible d'ouvrir le fichier $filename en lecture";
  123. while (my $line = <$fh>)
  124. {
  125. return $line;
  126. }
  127. close $fh;
  128. }
  129. else
  130. {
  131. return "pas d'information pour ". $fai ."\n";
  132. }
  133. }
  134. # lis le fichier et retourne le contenu
  135. sub lecture_fichier {
  136. my $fichier = shift @_;
  137. my $filename = $dir.$fichier;
  138. if (-e $filename)
  139. {
  140. my $fh;
  141. open ($fh, '<', $filename) or die "Impossible d'ouvrir le fichier $filename en lecture";
  142. while (my $line = <$fh>)
  143. {
  144. return $line;
  145. }
  146. close $fh;
  147. }
  148. else
  149. {
  150. return "Nope\n";
  151. }
  152. }
  153. # on compte le nombre d'adh et d'abo pour la fédé
  154. sub adh_abo_ffdn {
  155. my $filename = $dir."ffdn.adh";
  156. if (-e $filename)
  157. {
  158. my $fh;
  159. open ($fh, '<', $filename) or die "Impossible d'ouvrir le fichier $filename en lecture";
  160. while (my $line = <$fh>)
  161. {
  162. return $line;
  163. }
  164. close $fh;
  165. }
  166. else
  167. {
  168. return "pas d'information\n";
  169. }
  170. }
  171. # on note les RP
  172. sub rp {
  173. my $link = shift @_;
  174. my $filename = "/usr/share/nginx/www/rp.txt";
  175. my $filehandle;
  176. open ($filehandle, '>>', $filename) or die "Impossible d'ouvrir le fichier $filename en écriture";
  177. print $filehandle "$link\n";
  178. close $filehandle;
  179. return "Une nouvelle RP à traiter est disponible à http://unefede.fdn.fr/rp.txt (hl quota_atypique taziden)";
  180. }
  181. sub get_fai {
  182. my ($commande, $message) = @_;
  183. my @fai_trouves = grep { $message =~ /$regex{$_}/ } keys %regex;
  184. if (@fai_trouves < 1 ) {
  185. return "commande : ".$symbol."$commande <fai> (".$symbol."liste pour avoir la liste) ou ".$symbol."$commande <lieu geographique>";
  186. }
  187. elsif (@fai_trouves > 1 ) {
  188. return "Trop de fai trouvés : " . join ', ', @fai_trouves;
  189. }
  190. else {
  191. if ($commande eq 'info') {
  192. info $fai_trouves[0];
  193. }
  194. elsif ($commande eq 'adh') {
  195. adh $fai_trouves[0];
  196. }
  197. }
  198. }
  199. ## Le bot lit le chan et réagit
  200. sub said {
  201. my ($self, $message) = @_;
  202. # check if file was modified. if true we print this file when one user do
  203. # something on the chan.
  204. if (check::fichier("wrk-dir/suivi", 60)) {
  205. return("Il y a du nouveau pour la réunion de suivi. "
  206. . lecture_fichier("suivi"));
  207. }
  208. # si on veut des info
  209. if ($message->{body} =~ /^\Q$symbol\Einfo/) {
  210. shift @_;
  211. if($message->{body} =~ /$regex{"ffdn"}/i) {
  212. return "La fédération FDN regroupe des Fournisseurs d'Accès à Internet associatifs se reconnaissant dans des valeurs communes : bénévolat, solidarité, fonctionnement démocratique et à but non lucratif; défense et promotion de la neutralité du Net.";
  213. }
  214. get_fai 'info', $message->{body};
  215. }
  216. # si on veut le nombre d'adhérent
  217. elsif ($message->{body} =~ /^\Q$symbol\Eadh/) {
  218. shift @_;
  219. get_fai 'adh', $message->{body};
  220. }
  221. # si on veut de l'aide
  222. elsif ($message->{body} =~ /^\Q$symbol\Ehelp/) {
  223. return "commandes gérées : ".$symbol."liste, ".$symbol."info, ".$symbol."adh, ".$symbol."suivi, ".$symbol."vote, ".$symbol."source, ".$symbol."ag, ".$symbol."json, ".$symbol."rp";
  224. }
  225. # les sources du bot
  226. elsif ($message->{body} =~ /^\Q$symbol\Esource/) {
  227. lecture_fichier("source");
  228. }
  229. # les infos par rapport aux réunions de suivies
  230. elsif ($message->{body} =~ /^\Q$symbol\Esuivi/) {
  231. lecture_fichier("suivi");
  232. }
  233. # les infos par rapport aux réunions de suivies
  234. elsif ($message->{body} =~ /^\Q$symbol\Evote/) {
  235. lecture_fichier("vote");
  236. }
  237. # les infos par rapport à l'ag de la fédé
  238. elsif ($message->{body} =~ /^\Q$symbol\Eag/) {
  239. lecture_fichier("ag");
  240. }
  241. # les infos par rapport au source du bot
  242. elsif ($message->{body} =~ /^\Q$symbol\Ejson/) {
  243. lecture_fichier("json");
  244. }
  245. elsif ($message->{body} =~ /^\Q$symbol\Eliste/) {
  246. return "Les associations surveillées (par mes petits yeux de bot) sont : Ail-network, Apinnet, Aquilenet, ARN, Auvernet, CAFAI, Chaul-Hertz, FAImaison, FDN, Franciliens.net, GRIFON, Igwan, Ilico, Illyse, Iloth, LDN, NDN, Neutrinet, PC Light, Rezine, Rhizome, Sames Wireless, Teleragno, TDN et Tetaneutral";
  247. }
  248. # on assiste ceux qui ont alzheimer :p
  249. elsif ($message->{"body"} =~ /^symbol/) {
  250. return "Les symboles sont : pour UnRouteur : > ; pour moi-même : $symbol";
  251. }
  252. # easter egg
  253. elsif ($message->{body} =~ /datafoin/) {
  254. my @datafoin = (
  255. 'il ne faut pas me donner à manger après minuit /o\\',
  256. 'omnomnom',
  257. 'mais je vais grossir /o\\',
  258. 'vouiii',
  259. 'datafoin <3',
  260. );
  261. return $datafoin[int rand($#datafoin+1)];
  262. }
  263. elsif ($message->{body} =~ /^\Q$symbol\Erp/) {
  264. my $url = $message->{body};
  265. $url =~ s/^\Q$symbol\Erp //;
  266. rp($url);
  267. }
  268. }
  269. # tout ce qu'on écrit dans le ficher log apparait dans $channel
  270. sub connected {
  271. my $fichier = $dir."log";
  272. my $self = shift;
  273. $self->forkit({ channel => "#ffdn",
  274. run => [ qw( /usr/bin/tail -f -n0 /home/bot/bot-irc/wrk-dir/log ) ],
  275. });
  276. }
  277. # aucune idée de comment on déclenche cette ligne
  278. sub help { "Je suis le bot de la fédé." }
  279. #Info de connexion du bot
  280. MyBot->new(
  281. server => 'irc.geeknode.org',
  282. channels => [ '#fdn', '#ffdn', '#franciliens.net', '#faimaison', '#illyse'],
  283. nick => 'UneFede',
  284. username => 'bot',
  285. name => 'Droide de la Federation FDN, run by fédé'
  286. )->run();