aboutsummaryrefslogblamecommitdiffstats
path: root/libirc.c
blob: 284257ef13dedba3ada799098641d104137f75d7 (plain) (tree)
1
2
3
4
5
6
7
8
9
10
11
12
                                                   
                   
                   
                     







                       
                   


                                                                                 
                



                                                                
                       
 
                                                            
 




                                                                       
                                          
           

          
              
               
                      
                                        


                            
                                                      
                              
                   

                 




                                  
                                       
                     

                             
                       
   
                          
                                                                  
              
  

















                                                                         


                                                    
                                                                    

               
                                                                      



                

   
                                                                                  
           







                           


















                                                      





                                              





                                         


                                                          
                                         
                                                                              
   




                                                                         
 



                                   
 










                                                                                                                      
   
                         
           






















                                                                        




                                                                    
                 


















                                            
                                           






















                                                
#define _GNU_SOURCE //I want memmem out of string.h
#include <signal.h>
#include <string.h>
#include <sys/time.h>
#include <stdlib.h>
#include <stdio.h>
#include <netinet/in.h>
#include <netdb.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <sys/select.h>
#include <sys/un.h>

//epoch's lib includes:
#include <idc.h> //going to use this for mainloop instead of writing one in here.
#include "irc.h"

//#define DEBUG "epoch" //nick or channel to send debug info to.
#define CHUNK 4096

#define SILLYLIMIT 1024

//extern struct idc_global idc;//not sure if this is needed.

/* how this works:
if server == |/program then open a socketpair and fork and exec program
else try serv as IPv6, as IPv4, resolve as IPv6, resolve as IPv4
connect to that.
*/
int serverConnect(char *serv,char *port) {
 int fd=-1;
 int s[2];
 int pid;
 int try_ipv4;
 char *name[4];
 char buf[SILLYLIMIT];
 struct addrinfo hints, *servinfo, *p=0;
 struct hostent *he;
 struct sockaddr_in saddr;
 struct sockaddr_in6 saddr6;
 //printf("libirc: serverConnect: %s %s\n",serv,port);
 if(!serv || !port) return -1;
 if(*serv == '|') {
  name[0]=serv+1;
  name[1]=port;
  if((name[2]=strchr(port,' '))) {
   *name[2]=0;
   name[2]++;
   name[3]=0;
  }
  socketpair(PF_LOCAL,SOCK_STREAM,0,s);
  if(!(pid=fork())) {
   dup2(s[1],fileno(stdin));
   dup2(s[1],fileno(stdout));
   execv(name[0],name);
  }
  if(pid == -1) return -1;
  //printf("libirc: serverConnect: returning something! %d\n",fd);
  return s[0];
 }
 memset(&hints,0,sizeof hints);
 hints.ai_socktype=SOCK_STREAM;
 hints.ai_protocol=IPPROTO_TCP;
 for(try_ipv4=0;try_ipv4 < 2;try_ipv4++) {
  hints.ai_family=try_ipv4?AF_INET:AF_INET6;
  if(fd != -1) close(fd);
  if((fd=socket(hints.ai_family,SOCK_STREAM,IPPROTO_TCP)) < 0) return -1;
  if(!(he=gethostbyname2(
          try_ipv4
            ?inet_aton(serv,&(saddr.sin_addr))
              ?inet_ntoa(saddr.sin_addr)
              :serv
            :inet_pton(AF_INET6,serv,&(saddr6.sin6_addr))
              ?inet_ntop(AF_INET6,&(saddr6.sin6_addr),buf,SILLYLIMIT)
              :serv
          ,hints.ai_family))) continue;
  for(;*(he->h_addr_list);(he->h_addr_list)++) {
   inet_ntop(hints.ai_family,*(he->h_addr_list),buf,SILLYLIMIT);
   if(!getaddrinfo(buf,port,&hints,&servinfo)) {
    for(p=servinfo;p;p=p->ai_next) {
     if(connect(fd,p->ai_addr, p->ai_addrlen) < 0) {
      //printf("libirc: serverConnect: trying something else...\n");
      continue;
     } else {
      //printf("libirc: serverConnect: returning something! %d\n",fd);
      return fd;
     }
    }
   }
  }
 }
 //printf("I tried as hard as I could and couldn't connect to %s:%s\n",serv,port);
 return -1;
}

int fdlen(int *fds) {
 int i;
 for(i=0;fds[i] != -1;i++);
 return i+1;
}

char *memstr(char *s,char *find,size_t l) {
 return memmem(s,l,find,strlen(find));
}

/* already in string.h!
char *memmem(char *s,char *find,size_t sl,size_t fl) {
 size_t i,j,fl;
 if(!s) return 0;
 if(!find) return 0;
 for(i=0;i<l;i++) {
  for(j=0;j<fl;j++) {
   if(s[i] != find[j]) break;
  }
  if(j == fl) return s+i;
 }
 return 0;
}
*/

void (*g_line_handler)(); //kek
void (*g_extra_handler)(); //kek

int g_extra_fd;

void irc_handler(struct shit *me,char *line) {
//  fprintf(stderr,"debug: %s\n",line);
  if(!line) {
    //we're EOFd
    //we need to reconnect to the server.
    return;
  }
  if(!strncmp(line,"PING ",5)) {
    //I write back to the me->fd
    fprintf(stderr,"libirc: GOT A PING. SENDING PONG.\n");
    dprintf(me->fd,"PONG %s\r\n",line+5);
    return;//we probably don't need to let the bot know that it pinged. right?
  }
  //I need a way to get the line_handler passed to runem in here.
  g_line_handler(me->fd,line);
  //if(g_extra_handler) g_extra_handler(me->fd);///haxxxxxxxx fuck me.
  //GLOBALS. OFC. THAT IS THE RIGHT WAY TO DO IT. :D :D :D :D :D :D :D :|
}

void alarm_handler(int sig) {
  g_extra_handler(g_extra_fd);//???
  alarm(1);//lol
}

//is this really good enough to work? it doesn't have extra_handler use though.
int runem(int *fds,void (*line_handler)(),void (*extra_handler)()) { //wrap select_everything() so runem() still works
  g_line_handler=line_handler;
  g_extra_handler=extra_handler;
  g_extra_fd=fds[0];
  int i;
  //signal(SIGALRM,alarm_handler);
  //alarm(1);
  //initialization of this can't be in here. this gets ran after a tail is added.
  for(i=0;fds[i] != -1;i++) {
    add_fd(fds[i],irc_handler);
  }
  select_on_everything();
  return 1;
}

//wrap runem to keep runit around :P
int runit(int fd,void (*line_handler)(),void (*extra_handler)()) {
 int fds[2];
 fds[0]=fd;
 fds[1]=-1;
 return runem(fds,line_handler,extra_handler);
}

//not needed?
int ircConnect(char *serv,char *port,char *nick,char *user) {
 char sendstr[1024];
 int fd;
 fd=serverConnect(serv,port);
 if(!fd) {
  return 0;
 }
 snprintf(sendstr,sizeof(sendstr)-1,"NICK %s\r\nUSER %s