/* Acidblood network routines */ /* Acidblood IRC Bot Copyright (C) 1997 Bryan Schwab bryan@darkice.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 1, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include "acid.h" #include #include #include #include #include #include #include #include #include #include #include #include /* Small routine to get a single (newline or return terminated) line from the server using proper network calls This is still blocking.. i am planning on adding a select() call to make it a timeout function, and completly non blocking */ int gets_from_server(char *c ,int *s) { int x=0,len; struct timeval tv; fd_set infd; while(1) { tv.tv_sec=30; /* 30 second timeout */ tv.tv_usec=0; /* Setup the input descriptor for watch */ FD_ZERO(&infd); FD_SET(*s,&infd); len=select(*s+1,&infd,NULL,NULL,&tv); if(len) { recv(*s, &c[x], 1, 0); /* if(c[x]=='\r' || c[x]=='\n') break; */ /* since \n is the end of string delimiter, break here */ if(c[x]=='\n') break; x++; } else { /* Timeout */ return(-1); } } totalbytes+=x; return (x); } int getline_from_server(char *c ,int s) { int x=0,len; struct timeval tv; fd_set infd; tv.tv_sec=60*5; tv.tv_usec=0; /* Setup the input descriptor for watch */ FD_ZERO(&infd); FD_SET(s,&infd); c[0]='\0'; /* #ifdef DEBUG printf("Selecting...\n"); #endif */ while(1) { len=select(s+1,&infd,NULL,NULL,&tv); if(len > 0) { if(recv(s, &c[x], 1, 0) < 0) { perror("recv"); return(-1); } /* if(c[x]=='\r' || c[x]=='\n') { */ /* all strings end in \r\n, so look for the \n */ if(c[x]=='\n') { c[x]='\0'; break; } if (x > 1024) { /* hmm, looks like buffer got away somewhere, return an error */ return(-1); } x++; } else if (len == 0) { /* timeout */ return(-2); } else if (len == -1){ /* error */ return(-1); } } totalbytes+=x; /* #ifdef DEBUG printf("\n"); printf("Bytes=%d\n",x); printf("Total Bytes=%d\n",totalbytes); #endif */ return (x); } /* connect to the server */ /* at this point, everything is put into log files */ int connect_to_server( struct botstruct *botinfo, FILE **fp_socket, FILE **fp_log, int *s) { struct sockaddr_in sin; struct hostent *hp; char *input; char output[80]; char channel[20]; char temp[50]; char key[50]; char *tmpptr; char *codeptr; int code; char done=0; if ((input=malloc(1000))==NULL) { fprintf(stderr, "Malloc error!\n"); return(-1); } if ((hp=gethostbyname(botinfo->server)) == NULL) { fprintf(*fp_log, "Network Error: Unknown host %s\n",botinfo->server); return(-1); } if ((*s=socket(AF_INET,SOCK_STREAM,0)) < 0) { fprintf(*fp_log, "Network Error: Cannot create socket!\n"); return(-1); } sin.sin_family=AF_INET; sin.sin_port=htons(botinfo->port); bcopy(hp->h_addr, &sin.sin_addr, hp->h_length); /* timeout in 30 seconds */ alarm(30); if (connect(*s, (struct sockaddr *)&sin, sizeof(sin)) < 0) { fprintf(*fp_log, "Network Error: Cannot connect to port.\n"); return(-1); } /* reset alarm */ alarm(0); /* this could be removed */ if ((*fp_socket=fdopen(*s,"r"))==NULL) { return(-1); } sprintf(output,"USER %s %s +iw :%s\n",botinfo->user,botinfo->server,botinfo->fname); if ((send(*s,output,strlen(output),0))==-1) { return(-1); } sprintf(output,"NICK %s\n",botinfo->nick); if ((send(*s,output,strlen(output),0))==-1) { return(-1); } /* Now we have told the server all we should have to */ done=0; while(1) { gets_from_server(input, s); /* Set codeptr to point to the first character after the first space */ codeptr=strchr(input, ' ')+1; if(codeptr[0] >= '0' && codeptr[0] <= '9') sscanf(codeptr,"%d",&code); else code=-1; if(input[0]==':') { /* Message from server or user */ if(code > 0) { /* Numeric code from server */ switch(code) { case 1: /* Welcome */ /* We could pull the irc server name from this.. just so we have it */ break; case 433: /* Nick already in use */ if(strcmp(botinfo->nick, botinfo->altnick)==0) { fprintf(stderr,"Regular and alternate nick names are in use. Exiting.\n"); fprintf(*fp_log,"Regular and alternate nick names are in use. Exiting.\n"); /* This exit is a bit dangerous... nothin is free()ed */ exit(0); } fprintf(*fp_log,"Nickname is already in use, using alternate.\n"); sprintf(output,"NICK %s\n",botinfo->altnick); if ((send(*s,output,strlen(output),0))==-1) return(-1); /* set new bot nick pointer */ free(botinfo->nick); botinfo->nick=malloc(strlen(botinfo->altnick)); strcpy(botinfo->nick, botinfo->altnick); break; case 372: /* Motd body */ break; case 376: /* Motd end, this is where we stop trying to conenct to a server */ done=1; break; case 422: /* Motd missing */ done=1; break; } } else { /* PRIVMSG, etc, etc */ /* We aren't concerned about anything like that in here */ ; } } else if(memcmp(input,"PING",4)==0) { tmpptr=strtok(input,":"); tmpptr=strtok(NULL,"\n"); sprintf(output,"PONG :%s\n",tmpptr); if ((send(*s,output,strlen(output),0))==-1) { fprintf(*fp_log,"Error sending to server.\n"); exit(-1); } /* hmmmm, not good if we get an error! */ /* done=1; */ } else if(memcmp(input,"NOTICE",6)==0) { /* Ident, and other stuff in here. on efnet servers, this is an excellent place to put USER and NICK */ } else if (memcmp(input,"ERROR",5)==0) { fprintf(*fp_log,"%s",input); fflush(*fp_log); if ((strstr(input,"No Authorization"))!=NULL) { return(-2); } if ((strstr(input,"No more connections"))!=NULL) { return(-3); } if ((strstr(input, "Identd Required"))!=NULL) { return(-4); } if ((strstr(input, "Closing Link"))!=NULL) { return(-5); } } if(done) break; } curr3=top3; prev3=top3; if (botinfo->ns==1) {} else { while (get_channel(channeldata,temp,key) > 0) { sprintf(output,"JOIN %s %s\n",temp,key); if ((send(*s,output,strlen(output),0))==-1) { fprintf(*fp_log,"Error sending to server.\n"); return(-1); } } } /* if an away message exists, set away */ if (botinfo->awaymsg != NULL) { sprintf(output,"AWAY :%s\n",botinfo->awaymsg); if ((send(*s,output,strlen(output),0))==-1) { fprintf(*fp_log,"Error sending to server.\n"); return(-1); } } return(0); }