/*=============================================================*\ * ll.c - link looker * * Copyright (C) 1994 by The Software System and lilo * * Written by George Shearer (george@sphinx.biosci.wayne.edu) * * Cleaned up to usability by lilo. :) * * * * September, 1994 - added help, version info and made the * * program so you can actually use it. :) * * --lilo * * * * October 14, 1994 - cleaned up output flushing so you can * * actually watch in something like real * * time. :) --lilo * * * * October 28, 1994 - kill -1 will now produce a list of SPLIT * * servers. -Doc * * * * November 4, 1994 - should compile on non-POSIX systems now. * * use -DHPSUCKS for HP-sUX systems 9.0x * * November 15, 1994 - fixed a small bug in lilo's -h checker * \*=============================================================*/ /* 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 2 of the License, 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. */ /* Compiling examples: regular old ANSI/C cc: cc -O -s -o ll ll.c HP-UX cc: cc +O3 -Aa -s -DHPSUCKS -o ll ll.c GNU GCC: Linux: gcc -O2 -fomit-frame-pointer -funroll-loops -m486 -s -Wall -o ll ll.c BSD, SunOS 4.1.x, Slowaris 2.x, NeXT: gcc -O2 -funroll-loops -s -Wall -o ll ll.c */ #define VERSION "1.06" #define BUFSIZE 400 /* IRC Server buffer */ #define SERVER "irc.escape.com" /* IRC Server */ #define PORT 6667 /* IRC Port */ #define LDELAY 30 /* Loop delay seconds*/ #define TIMEOUT 30 /* connection timeout*/ #define ESTABLISHED 1 #define INPROGRESS 2 #define SPLIT 1 #ifdef HPSUCKS #define _INCLUDE_HPUX_SOURCE #define _INCLUDE_XOPEN_SOURCE #define _INCLUDE_POSIX_SOURCE #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include unsigned short int session=0,link_count=0; char in[BUFSIZE],out_buf[BUFSIZE],hostname[64]; char *ins=in; char serverhost[81], nick[10], user[10], realname[81], lasttime[81]; time_t ltime; struct irc_server { char *name; char *link; unsigned short int status; time_t time; struct irc_server *next; } *sl1=(struct irc_server *)0,*sl2=(struct irc_server *)0; void do_ping(char *,char *); void do_001(char *,char *); void do_error(char *,char *); void do_364(char *,char *); void do_365(char *,char *); /* prototyping is lame when the function is in the same code, lilo outta just move the function before all other functions that call it :-) */ char *stamp(time_t); struct parsers { char *cmd; void (*func)(char *,char *); } parsefuns[] = { { "PING", (void (*)())do_ping }, { "001", (void (*)())do_001 }, { "364",(void (*)())do_364 }, { "365", (void (*)())do_365}, { "ERROR",(void (*)())do_error}, { (char *)0,(void (*)())0 } }; struct sockaddr_in server; int sock=0; #ifndef sys_errlist extern char *sys_errlist[]; #endif #ifndef errno extern int errno; #endif char * mystrerror(int err) { return(sys_errlist[err]); } unsigned long int resolver(char *host) { unsigned long int ip=0L; if(host && *host && (ip=inet_addr(host))==-1) { struct hostent *he; int x=0; while(!(he=gethostbyname((char *)host)) && x++<3) { fprintf(stderr,"."); fflush(stderr); sleep(1); } ip=(x<3) ? *(unsigned long *)he->h_addr_list[0] : 0L; } return(ip); } void clean_sl2(void) { while(sl2) { struct irc_server *temp=sl2->next; if(sl2->name) free(sl2->name); if(sl2->link) free(sl2->link); free(sl2); sl2=temp; } sl2=(struct irc_server *)0; } void exit_program(char *why) { fprintf(stderr,"\nExiting program. (%s)\n",why); if(sock) close(sock); while(sl1) { struct irc_server *temp=sl1->next; if(sl1->name) free(sl1->name); if(sl1->link) free(sl1->link); free(sl1); sl1=temp; } clean_sl2(); if(in) free(in); exit(0); } int mystrccmp(register char *s1,register char *s2) { while((((*s1)>='a'&&(*s1)<='z')?(*s1)-32:*s1)== (((*s2)>='a'&&(*s2)<='z')?(*s2++)-32:*s2++)) if(*s1++==0) return 0; return (*(unsigned char *)s1-*(unsigned char *)--s2); } char *mstrcpy(char **to,char *from) { if(from) { if((*to=(char *)malloc(strlen(from)+1))) strcpy(*to,from); } else *to=(char *)0; return(*to); } char *digtoken(char **string,char *match) { if(string && *string && **string) { while(**string && strchr(match,**string)) (*string)++; if(**string) { /* got something */ char *token=*string; if((*string=strpbrk(*string,match))) { *(*string)++=(char)0; while(**string && strchr(match,**string)) (*string)++; } else *string = ""; /* must be at the end */ return(token); } } return((char *)0); } void signal_handler(void) { exit_program("caught signal"); } void signal_alarm(void) { exit_program("timed out waiting for server interaction."); } void out(void) { int length=strlen(out_buf); errno=0; if(write(sock,out_buf,length)!=length) exit_program(mystrerror(errno)); } void init_server(void) { int length; sprintf(out_buf,"USER %s %s %s :%s\nNICK %s\nMODE %s +is", \ user, user, user, realname, nick, nick); length=strlen(out_buf); errno=0; if(write(sock,out_buf,length)==length) { fputs("established\n",stderr); session=ESTABLISHED; alarm(TIMEOUT); sprintf(out_buf,"LINKS\n"); out(); } else exit_program(mystrerror(errno)); } void heartbeat(void) { strcpy(out_buf,"LINKS\n"); out(); signal(SIGALRM,(void (*)())heartbeat); alarm(LDELAY); } void do_364(char *from,char *left) { struct irc_server *serv; char *sv1,*sv2; char *nick; serv=(struct irc_server *)malloc(sizeof(struct irc_server)); serv->next=sl2; serv->status=0; nick=digtoken(&left," "); sv1=digtoken(&left," "); sv2=digtoken(&left," "); mstrcpy(&serv->name,sv1); mstrcpy(&serv->link,sv2); sl2=serv; } int findserv(struct irc_server *serv,char *name) { for(;serv;serv=serv->next) if(!mystrccmp(name,serv->name)) return(1); return(0); } void show_split(void) { struct irc_server *serv=sl1; signal(SIGHUP,(void (*)())show_split); for(;serv;serv=serv->next) { if(serv->status & SPLIT) { printf("%s SPLIT: %s [%s]\n",stamp(serv->time),serv->name,serv->link); fflush(stdout); } } } void do_365(char *from,char *left) { struct irc_server *serv=sl1; for(;serv;serv=serv->next) { if(!findserv(sl2,serv->name)) { if(!(serv->status & SPLIT)) { serv->time=time(NULL); printf("%s SPLIT: %s [%s]\n",stamp(serv->time),serv->name,serv->link); fflush(stdout); serv->status|=SPLIT; } } else if(serv->status & SPLIT) { serv->time=time(NULL); printf("%s MERGE: %s [%s]\n",stamp(serv->time),serv->name,serv->link); fflush(stdout); serv->status&=~SPLIT; } } serv=sl2; for(;serv;serv=serv->next) { if(!findserv(sl1,serv->name)) { struct irc_server *serv2; serv2=(struct irc_server *)malloc(sizeof(struct irc_server)); serv2->next=sl1; serv2->status=0; mstrcpy(&serv2->name,serv->name); mstrcpy(&serv2->link,serv->link); sl1=serv2; serv2->time=time(NULL); if(link_count) { printf("%s ADDED: %s [%s]\n",stamp(serv2->time),serv->name,serv->link); fflush(stdout); } } } link_count=1; clean_sl2(); } void do_ping(char *from,char *left) { sprintf(out_buf,"PING :%s\n",hostname); out(); } void do_001(char *from,char *left) { fprintf(stderr,"Logged into server %s as nickname %s\n\n",from,nick); fflush(stderr); alarm(0); signal(SIGALRM,(void (*)())heartbeat); alarm(LDELAY); } void do_error(char *from,char *left) { fprintf(stderr,"Server error: %s\n",left); fflush(stderr); } void parse2(void) { char *from,*cmd,*left; if(*ins==':') { if(!(cmd=strchr(ins,' '))) return; *cmd++=(char)0; from=ins+1; } else { cmd=ins; from=(char *)0; } if((left=strchr(cmd,' '))) { int command; *left++=(char)0; left=(*left==':') ? left+1 : left; for(command=0;parsefuns[command].cmd;command++) { if(!mystrccmp(parsefuns[command].cmd,cmd)) { parsefuns[command].func(from,left); break; } } } } void parse(int length) { char *s=in; *(ins+length)=(char)0; for(;;) { ins=s; while(*s && *s!=(char)13 && *s!=(char)10) s++; if(*s) { while(*s && (*s==(char)13 || *s==(char)10)) *s++=(char)0; parse2(); } else break; } strcpy(in,ins); ins=in+(s-ins); } void process_server(void) { int x=0; for(;;) { fd_set rd,wr; struct timeval timeout; timeout.tv_usec=0; timeout.tv_sec=1; FD_ZERO(&rd); FD_ZERO(&wr); FD_SET(sock,&rd); if(session==INPROGRESS) FD_SET(sock,&wr); errno=0; #ifdef HPSUCKS select((size_t)FD_SETSIZE,(int *)&rd,(int *)&wr,(int *)0,(session==INPROGRESS)?(const struct timeval *)&timeout:(const struct timeval *)0); #else select(getdtablesize(),(fd_set *)&rd,(fd_set *)&wr,(fd_set *)0,(session==INPROGRESS)?(struct timeval *)&timeout:(struct timeval *)0); #endif if(errno==EINTR) continue; errno=0; if(session==INPROGRESS) { if(FD_ISSET(sock,&wr)) { init_server(); continue; } else { if(x++>=TIMEOUT) exit_program("connection timed out"); fprintf(stderr,"."); fflush(stderr); } } if(FD_ISSET(sock,&rd)) { int length=read(sock,ins,BUFSIZE-(ins-in)); if(length<1) { if(session!=INPROGRESS) { if(!errno) { fputs("Connection closed by foreign host.",stderr); errno=ENOTCONN; } else fprintf(stderr,"Connection to %s closed.\n", inet_ntoa(server.sin_addr)); fflush(stderr); } exit_program(mystrerror(errno)); } if(strpbrk(in,"\x0a\x0d")) parse(length); else ins=(BUFSIZE-((ins+length)-in)<1)?in:ins+length; } } } char *stamp(time_t ltime) { strftime(lasttime, 81, "%x %X", localtime(<ime)); return (char *) &lasttime; } void main(int argc,char *argv[]) { unsigned short int sport=PORT; unsigned int loop; struct passwd *passent; fprintf(stderr, "Link Looker v%s, written and designed by Dr. Delete.\n" \ " Enhanced by lilo.\n" \ "Type '%s -h' or '%s --help' for more information.\n\n", VERSION, argv[0], argv[0]); for(loop=1; loop [[:] ['' " \ "[]]]]\n\n where:\n\n" \ " is the nickname to be used (default is userid),\n" \ " is the hostname of the server to be used,\n" \ " is a four digit port number (default is 6667),\n" \ " is a description of the user (default is gecos info), and\n" \ " is the user account field, used only if identd\n" \ " has not been enabled on the user's system.\n", \ argv[0]); exit(1); } } passent=getpwuid(getuid()); if(argc>1) strncpy(nick,argv[1],9); else strncpy(nick,passent->pw_name,9); if(argc>2) { char *port=strchr(argv[2],':'); sport=(port)?atoi(port+1):sport; strncpy(serverhost,argv[2],80); if(port) serverhost[port-argv[2]]=(char)0; } else strncpy(serverhost,SERVER,80); if(argc>3) strncpy(realname,argv[3],80); else { char *comma=strchr(passent->pw_gecos,','); strncpy(realname,passent->pw_gecos,80); if(comma) realname[comma-(passent->pw_gecos)]=(char)0; } if(argc>4) strncpy(user,argv[4],9); else strncpy(user,passent->pw_name,9); signal(SIGPIPE,(void (*)())signal_handler); signal(SIGHUP,(void (*)())show_split); signal(SIGINT,(void (*)())signal_handler); signal(SIGTERM,(void (*)())signal_handler); signal(SIGBUS,(void (*)())signal_handler); signal(SIGABRT,(void (*)())signal_handler); signal(SIGSEGV,(void (*)())signal_handler); signal(SIGALRM,(void (*)())signal_alarm); errno=0; if((sock=socket(AF_INET,SOCK_STREAM,0))>0) { server.sin_family=AF_INET; server.sin_port=htons(sport); fprintf(stderr,"Resolving %s...",serverhost); fflush(stderr); if((server.sin_addr.s_addr=resolver(serverhost))) { fputs("done\n",stderr); fflush(stderr); setsockopt(sock,SOL_SOCKET,SO_LINGER,0,0); setsockopt(sock,SOL_SOCKET,SO_REUSEADDR,0,0); setsockopt(sock,SOL_SOCKET,SO_KEEPALIVE,0,0); fcntl(sock,F_SETFL,(fcntl(sock,F_GETFL)|O_NDELAY)); fprintf(stderr,"Connecting to %s...",inet_ntoa(server.sin_addr)); fflush(stderr); errno=0; if(connect(sock,(struct sockaddr *)&server,sizeof(server))) { if(errno!=EINPROGRESS && errno!=EWOULDBLOCK) exit_program(mystrerror(errno)); else session=INPROGRESS; } else init_server(); gethostname(hostname,64); process_server(); } else exit_program("resolve failed"); } else { fprintf(stderr,"Failed to allocate an AF_INET socket. (%s)\n", \ mystrerror(errno)); fflush(stderr); } }