Bot irc : marche sous win et sous linux sans changement

Contenu du snippet

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 !

A voir également

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.