Voici un joli bot IRC qui va sur .. IRC :)
Ce code peut etre compilé sous Dev-c++(gcc donc) , sous Vc++ 6 , et GCC sous linux :p Le code est fait de telle maniere kil marche sous linux !
Je n' ai pas testé d' autres compilateurs (testez les pour moi)...
Il y a peu de fonctions mais ce bot est facile a améliorer !
Il peut etre multiserver vu qu' il utilise des socket asynchrones .
chez moi le code est séparé dans différents .c et .h mais je l ai mis en un seul fichier pour que ceux qui ne sont pas enregistrés le voient :)
Allez bon amusement (lol)
Source / Exemple :
/********************************************************************/
/*** IrrealBot v1.0: ***/
/*** Se compile sous nux avec gcc ou sous win avec gcc ou vc++ ***/
/*** ***/
/*** Version de démonstration : peu de fonctions implémentées ***/
/*** Les fonctions sont normalement réparties dans plusieurs .c ***/
/*** Mais jai ici tout rassemblé pour cppfrance.com (pour ke les ***/
/*** non enregistrés puissent visualiser le code :) ***/
/*** Bon mattez le code maintenant :p ***/
/*** ***/
/*** Pour l'utiliser: ***/
/*** ./bot serveur port nick chan founder [ident] [nom réel] ***/
/*** exemple : ./bot irc.freenode.net 6667 botirc linux groar ***/
/*** ***/
/*** l ident et le nom réel ne sont pas obligatoires ***/
/*** /!\ le Chan ne doit pas avoir de # ;) car sous nux ca ***/
/*** fait bugger ***/
/********************************************************************/
/* Les includes communs a windows et linux */
#include <stdio.h>
#include <string.h>
/* includes de windows */
#ifdef WIN32
#include <winsock.h>
typedef unsigned int u_int32_t; /* utilisé par linux mais non défini dans winsock.h */
/* les includes de linux */
#else
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <sys/types.h>
#define SOCKET_ERROR (-1) /* défini dans winsock.h */
typedef struct sockaddr_in SOCKADDR_IN; /* idem */
#endif
/* différentes commandes IRC */
#define IRC_USER "USER %s %s %s :%s\n"
#define IRC_NICK "NICK %s\n"
#define IRC_MSG "PRIVMSG %s :%s\n"
#define IRC_JOIN "JOIN %s\n"
#define IRC_PART "PART %s\n"
#define PING_CMD "PING :%s\n"
#define PONG_CMD "PONG :%s\n"
#define IRC_QUIT "QUIT :%s\n"
/* structure définissant un utilisateur IRC : plus pratique */
typedef struct irc_user{
char *nick;
char *ident;
char *name;
char *host;
}irc_user;
/* quelques fonctions maison */
int my_sock_init();
char *my_sock_recv_line(int sock);
int my_sock_client(char Fip[],int port);
int my_error(char *file,int line,int severity,char *texte);
char *my_last_arg(char *chaine);
char *strleft(char *chaine,int lft) ;
/* fonction servant a se connecter a un server irc */
int irc_connect(char *serveur,int port,irc_user u1,char *chan);
int irc_shell(int sock1,char *master); // la fonction traitant les commandes du bot
/* commandes du parser: on lui donne a manger ce que nous envoie le serveur et nous renvoie : */
char *parser_get_nick(char *data); // le nick de celui ki a executé une commande
char *parser_get_ident(char *data); // son ident
char *parser_get_host(char *data) ; // son host :p
char *parser_get_cmd(char *data); // la commande (NOTICE,PRIVMSG,etc...)
char *parser_get_dest(char *data); // la destination : le chan ou le nick a qui est adressé la commande
char *parser_get_buf(char *data); // ce qui est envoyé (le message par exemple)
/* J ai délibérément utilisé ici des int a la place des SOCKET (les SOCKET sont des int) pour que cela
ressemble un peu plus au code linux (souvenez vous que ce code compile également sous linux */
int main(int argc, char *argv[])
{
irc_user bot;
int retval=0;
int mainsock; // le sock utilisé du debut a la fin
char *chan; // buffer pour recevoir le chan + le # ki va avec ;)
if(argc < 6) // si on a pas mis tous les arguments obligatoires
{
printf("USAGE: %s <serveur> <port> <nick> <chan> <propriétaire> [ident] [name]\n",argv[0]);
return (-1);
}
if(argc == 6) // si ya pas d ident et de name
{
bot.ident = "default";
bot.name = "Je suis irréel";
}
if(argc == 7) // si ya pas de name
{
bot.ident = (char *)malloc(strlen(argv[6]));
bot.ident = argv[6];
bot.name = "Je suis irréel";
}
if(argc == 8) // si ya tout
{
bot.ident = (char *)malloc(strlen(argv[6]));
bot.ident = argv[6];
bot.name = (char *)malloc(strlen(argv[7]));
bot.name = argv[7];
}
bot.nick = (char *)malloc(strlen(argv[3])); // jaime bien les malloc (sinon ca segfault souvent sous nux)
bot.nick = argv[3];
bot.host = "abyssal"; // sert a rien
chan =(char *)malloc(strlen(argv[4]) + 2);
sprintf(chan,"#%s",argv[4]); // on prend le nom du chan et on rajoute le # devant
while(retval != 1)
{
mainsock = irc_connect(argv[1],atoi(argv[2]),bot,chan); // on connecte a irc et on renvoit une socket
retval = irc_shell(mainsock,argv[5]); // le sock est reutilisé dans le shell
}
return 0;
}
// FONCTION irc_connect
int irc_connect(char *serveur,int port,irc_user u1,char *chan)
{
int sock1;
int i;
char *buf_send=(char *)malloc(sizeof(char)*50); // le buffer avec lekel on envoit les données
char *buf_recv=(char *)malloc(sizeof(char)); // le buffer dans lequel sont stockées les données recues
char *tmpbuf;
#ifdef WIN32
my_sock_init(); // fonction seulement pour win
#endif
sock1 = my_sock_client(serveur,port); // on fait une connection cliente
sprintf(buf_send,IRC_USER,u1.ident,u1.nick,u1.nick,u1.name);
// on envoit la commande USER
if(send(sock1,buf_send,strlen(buf_send),0) == SOCKET_ERROR)
my_error(__FILE__,__LINE__,0,"Send Error");
sprintf(buf_send,IRC_NICK,u1.nick);
// on envoit la commande NICK
if(send(sock1,buf_send,strlen(buf_send),0) == SOCKET_ERROR)
my_error(__FILE__,__LINE__,0,"send error");
buf_recv=(char *)my_sock_recv_line(sock1);
if((tmpbuf = strstr(buf_recv,"PING")) != NULL) // si PING on repond
{
printf("PING ? PONG !\n");
tmpbuf[1]='O';
send(sock1,tmpbuf,strlen(tmpbuf),0);
}
for(i=0;i<1000;i++); // c un temps d attente c tout :)
sprintf(buf_send,IRC_JOIN,chan); // on join le chan demandé
if(send(sock1,buf_send,strlen(buf_send),0) == SOCKET_ERROR)
my_error(__FILE__,__LINE__,0,"send error");
return sock1;
}
int irc_shell(int sock2,char *master)
{
int sock1 = sock2;
int retval = 0;
char *buf_send=(char *)malloc(sizeof(char)*50);
char *buf_recv=(char *)malloc(sizeof(char));
char *tmpbuf,*buf2;
struct timeval tv;
fd_set rfds;
tv.tv_sec=0; // on va attendre 0seconde
tv.tv_usec=0; // et 0 µs :)
while(retval == 0)
{
FD_ZERO(&rfds); // on met a zero le fd_set
FD_SET(sock1,&rfds); // on ajoute sock1 kommme descripteur a l ensemble
select(sock1 + 1,&rfds,NULL,NULL,&tv); // man select :]
/* est ce qu on sock1 a subi un changement (arrivée de données par exemple) */
if(FD_ISSET(sock1,&rfds))
{
buf_recv=(char *)my_sock_recv_line(sock1); // on recoit une ligne
if((parser_get_cmd(buf_recv)) != NULL)
{if((strcmp(parser_get_cmd(buf_recv),"PRIVMSG")) == 0) // si la commande est un PRIVMSG
printf("<%s> %s\r\n",parser_get_nick(buf_recv),parser_get_buf(buf_recv)); }
// on affiche facon mirc :)
if((tmpbuf = strstr(buf_recv,"PING")) != NULL) // PING ? PONG !
{
tmpbuf[1]='O';
send(sock1,tmpbuf,strlen(tmpbuf),0);
printf("PING ? PONG !\n");
}
// si le nick de celui ki parle est celui ki controle le bot
if((strcmp(parser_get_nick(buf_recv),master)) == 0)
{
if((tmpbuf = strstr(buf_recv,"!join")) != NULL)
{
if((buf2 = strstr(tmpbuf," ")) != NULL) // ca prend tout ce kya apres le !join
{
// strleft me sert ici a enlever l espace devant le chan
printf("*** JOINING %s",strleft(buf2,1));
sprintf(buf_send,IRC_JOIN,strleft(buf2,1));// cmd JOIN
send(sock1,buf_send,strlen(buf_send),0); // on join le chan
}
}
if((tmpbuf = strstr(buf_recv,"!part")) != NULL) // idem avec part
{
if((buf2 = strstr(tmpbuf," ")) != NULL)
{
printf("*** PARTING %s",strleft(buf2,1));
sprintf(buf_send,IRC_PART,strleft(buf2,1));
send(sock1,buf_send,strlen(buf_send),0);
}
}
// quit qui en + de faire partir du serv fait sortir du while
if((tmpbuf = strstr(buf_recv,"!quit")) != NULL)
{
if((buf2 = strstr(tmpbuf," ")) != NULL)
{
printf("*** QUIT(%s)",strleft(buf2,1));
sprintf(buf_send,IRC_QUIT,strleft(buf2,1));
send(sock1,buf_send,strlen(buf_send),0);
retval = 1;
}
}
if((tmpbuf = strstr(buf_recv,"!exit")) != NULL)
{
send(sock1,"QUIT\n",strlen("QUIT\n"),0);
retval = 2;// avec ca le bot quit et revient
}
if((tmpbuf = strstr(buf_recv,"!say")) != NULL)
{
if((buf2 = strstr(tmpbuf," ")) != NULL)
{
printf("*** %s",strleft(buf2,1));
sprintf(buf_send,IRC_MSG,parser_get_dest(buf_recv),strleft(buf2,1));
send(sock1,buf_send,strlen(buf_send),0);
}
}
// ex: !raw PRIVMSG #groar :lol <-- raw sert a envoyer des donneés au server
if((tmpbuf = strstr(buf_recv,"!raw")) != NULL)
{
if((buf2 = strstr(tmpbuf," ")) != NULL)
{
printf("RAW :%s",buf2);
sprintf(buf_send,strleft(buf2,1));
send(sock1,buf_send,strlen(buf_send),0);
}
}
if((tmpbuf = strstr(buf_recv,"!nick")) != NULL) // change de nick
{
printf("*** je change de nick : %s",my_last_arg(tmpbuf));
sprintf(buf_send,IRC_NICK,my_last_arg(tmpbuf));
send(sock1,buf_send,strlen(buf_send),0);
}
}
}
else
{ // si vous avez kelke chose a mettre :p
}
}
#ifdef WIN32
closesocket(sock1); // facon win
#else
close(sock1); // facon nux
#endif
return retval;
}
char *parser_get_nick(char *data)
{
char *buf=(char *)malloc(100*sizeof(char));
char *delimit = ":!" ;
char *buf1 = strdup(data);
buf = strtok(buf1, delimit); // on prend le char * entre le : et le !
return (char *)buf; // c le nick
}
char *parser_get_ident(char *data)
{ // meme systeme : man strtok
char *buf;
char *delimit = "~@" ;
char *buf1 = strdup(data);
buf = strtok(buf1, ":!");
buf = strtok(NULL, delimit);
return (char *)buf;
}
char *parser_get_host(char *data)
{
char *buf;
char *delimit = " " ;
char *buf1 = strdup(data);
buf = strtok(buf1, ":!");
buf = strtok(NULL, "~@");
buf = strtok(NULL, delimit);
return (char *)buf;
}
char *parser_get_cmd(char *data)
{
char *buf;
char *delimit = " " ;
char *buf1 = strdup(data);
buf = strtok(buf1, ":!");
buf = strtok(NULL, "~@");
buf = strtok(NULL, " ");
buf = strtok(NULL, delimit);
return (char *)buf;
}
char *parser_get_dest(char *data)
{
char *buf;
char *delimit = ":" ;
char *buf1 = strdup(data);
buf = strtok(buf1, ":!");
buf = strtok(NULL, "~@");
buf = strtok(NULL, " ");
buf = strtok(NULL, " ");
buf = strtok(NULL, delimit);
return (char *)buf;
}
char *parser_get_buf(char *data)
{
char *buf;
char *delimit = "\n" ;
char *buf1 = strdup(data);
buf = strtok(buf1, ":!");
buf = strtok(NULL, "~@");
buf = strtok(NULL, " ");
buf = strtok(NULL, " ");
buf = strtok(NULL, ":");
buf = strtok(NULL, delimit);
return (char *)buf;
}
// decale une char * vers la gauche : exemple : strleft("groar",1); = roar
char *strleft(char *chaine,int lft)
{
int i = 0;
char *buf = (char *)malloc(strlen(chaine) - lft);
for(i = lft; i < strlen(chaine); i++)
{
buf[i - lft] = chaine[i];
}
return (char *)buf;
}
// avec ca on recoit ligne par ligne ce ke le serv envoie
char *my_sock_recv_line(int sock)
{
int pos = 0;
char c;
int buf_len;
char *buf_str;
buf_str = (char *)malloc(10 * sizeof(char));
buf_len = 10;
c = '\0';
while(c != '\n')
{
recv(sock,&c,sizeof(char),0);
buf_str[pos] = c;
pos++;
if(pos == buf_len)
{
buf_len += 10;
buf_str = (char *)realloc(buf_str,buf_len * sizeof(char));
}
}
buf_str[pos] = '\0';
return (char *)buf_str;
}
int my_sock_client(char Fip[],int port) // pour se connnect a un serv
{
int s;
unsigned int addr;
struct hostent *hp;
struct sockaddr_in sin;
if (isalpha(Fip[0]))
hp=gethostbyname(Fip);
else
{
addr = inet_addr(Fip);
hp = gethostbyaddr((char *)&addr,4,AF_INET);
}
sin.sin_addr.s_addr = *((u_int32_t *) hp->h_addr);;
sin.sin_family = AF_INET;
sin.sin_port=htons(port);
s = socket(PF_INET, SOCK_STREAM, 0);
if (connect(s,(struct sockaddr *)&sin,sizeof(SOCKADDR_IN))==SOCKET_ERROR)
my_error(__FILE__,__LINE__,0,"erreur de connect");
return s;
}
char *my_last_arg(char *chaine) // retourne le dernier mot d une chaine
{
char* p;
char* buffer,*temp;
char* separateurs = { " " };
buffer = strdup(chaine);
p = strtok( buffer, separateurs );
temp = (char *)malloc(strlen(p)+1);
while((p = strtok( NULL, separateurs )) != NULL )
{
free(temp);
temp = (char *)malloc(strlen(p)+1);
sprintf(temp,p);
}
return (char*)temp;
}
// erreur : c pourri comme error mais bon
int my_error(char *file,int line,int severity,char *texte)
{
printf("%s:%d # %s\n",file,line,texte);
return 0;
}
int my_sock_init() // init pour winsock
{
#ifdef WIN32
WSADATA wsaData;
WORD verreq;
verreq=MAKEWORD(2,2);
if(WSAStartup(verreq,&wsaData) != 0)
return -1;
#endif
return 0;
}
Conclusion :
Je ne sais pas qi je ferai une mise a jour mais bon :)
Sinon go on
http://abyssal.homelinux.org/
utilisation :
./bot serveur port nick chan founder [ident] [name]
ex: ./bot Faubourg.FR.EU.Kewl.Org 6667 nickbot abyssal groar urk urkloul
il faut enlever le # du chan sinon sous nux ca ne marchait pas ;)
Quelques bugs que je n ai pas corrigés :
quand l ident ou le real name est trop long ca plante :)
lEs GreeTz: swivelleroo,errno,phun(mdr si tu vois ca toi),slythers,[belou],mon chat,#abyssal,#include,#osdev-fr,et les autres chans !
madchat,dautres sites aussi !
Vous n'êtes pas encore membre ?
inscrivez-vous, c'est gratuit et ça prend moins d'une minute !
Les membres obtiennent plus de réponses que les utilisateurs anonymes.
Le fait d'être membre vous permet d'avoir un suivi détaillé de vos demandes et codes sources.
Le fait d'être membre vous permet d'avoir des options supplémentaires.