/* * ircaux.c: some extra routines... not specific to irc... that I needed * * Written By Michael Sandrof * * Copyright (c) 1990, 1991 Michael Sandrof. * Copyright (c) 1991, 1992 Troy Rollo. * Copyright (c) 1992-2003 Matthew R. Green. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $Id: ircaux.c,v 1.18 2003/12/24 11:12:10 f Exp $ */ #include "irc.h" #if defined(ESIX) || defined(MIPS_SYSV) # define _TERMIOS_INCLUDED # define _INCLUDE_TERMIO # include #endif #ifdef HAVE_SYS_UN_H #include #endif /* HAVE_SYS_UN_H */ #ifndef _Windows #include #endif /* _Windows */ #include "ircaux.h" #include "output.h" #include "ircterm.h" #include "newio.h" /**************************** PATCHED by Flier ******************************/ int DCCLowPort; int DCCHighPort; /****************************************************************************/ #ifdef INET6 extern char FAR MyHostName[]; static int bind_local_addr _((char *, char *, int, int)); #else extern struct in_addr MyHostAddr; #endif extern char *source_host; #ifdef ALLOC_DEBUG # ifdef _IBMR2 struct HeapDesc { u_long Link; u_long Size; }; # endif #define ALLOC_LIST 2048 static u_char *MemList[ALLOC_LIST]; static long MemSize[ALLOC_LIST]; static int Init = 0; static void dump_mem _((void)); static void dump_mem() { int i; FILE *fp; #ifdef _IBMR2 struct HeapDesc *HeapElement; char *lowest; char *highest; long size; #endif int fits; fp = fopen("debug.log", "w"); fprintf(fp, "ircII failed because of a segmentation violation\nKnown allocations follow:\n\n"); for (i = 0; i < ALLOC_LIST; i++) if (MemList[i]) { #ifdef _IBMR2 /* * The following determines if the size shown for this element of * memory matches the size we have recorded in the allocation list. * this is very much machine dependant, and could even vary between * SysV and BSD on the same machine. */ size = (0x08 << (*((long *) MemList[i] - 1))); if (size - 0x08 >= MemSize[i] && (size >> 1) - 0x08 (u_long) highest) highest = MemList[i]; } fprintf(fp, "\nKnown allocations start at %08x and end at %08x\n", lowest, highest); fprintf(fp, "\nHeap walks as follows:\n\n"); for (HeapElement = lowest-0x08; HeapElementLink == 0xefL || !HeapElement->Link)? (HeapElement+(0x01<Size)): ((struct HeapDesc *) HeapElement->Link)) { fprintf(fp, " %08x %08x %08x\n", HeapElement + 1, HeapElement->Link, HeapElement->Size); } #endif fclose(fp); fprintf(stderr, "Segmentation violation. Debug information saved to debug.log\n"); /* * If we resume on a segmentation violation, hopefully it repeats the * violation and we get both our log and the core dump from the point * at which things fail. */ (void) MY_SIGNAL(SIGSEGV, (sigfunc *)SIG_DFL, 0); return; } #endif /* * new_free: Why do this? Why not? Saves me a bit of trouble here and * there */ void new_free(iptr) void *iptr; { void **ptr = (void **) iptr; #ifdef ALLOC_DEBUG FILE *fp; int i; #endif /**************************** PATCHED by Flier ******************************/ /*#ifdef DO_USER2 int oldmask; #endif*/ /* DO_USER2 */ /****************************************************************************/ if (*ptr == empty_string) *ptr = (void *) 0; else if (*ptr) { /**************************** PATCHED by Flier ******************************/ /*#ifdef DO_USER2 oldmask = sigblock(sigmask(SIGUSR2)); #endif*/ /* DO_USER2 */ /****************************************************************************/ #ifdef FREE_DEBUG if (free(*ptr) < 0) put_it("*debug* free failed '%s'", (char *) ptr); #else free(*ptr); #endif /**************************** PATCHED by Flier ******************************/ /*#ifdef DO_USER2 sigblock(oldmask); #endif*/ /* DO_USER2 */ /****************************************************************************/ #ifdef ALLOC_DEBUG for (i = 0; i < ALLOC_LIST; i++) { if ((void *) MemList[i] == *ptr) break; } if (i == ALLOC_LIST) { fprintf(stderr, "Memory freed that was never allocated\n"); fp=fopen("debug.log", "w"); fprintf(fp, "failed by freeing %08lx\n", (long) *ptr); fprintf(fp, "List is as follows:\n"); for (i = 0; i < ALLOC_LIST; i++) if (MemList[i]) fprintf(fp, " %08lx %08lx\n", (long) MemList[i], MemSize[i]); fclose(fp); abort(); } MemList[i] = (void *) 0; MemSize[i] = 0L; #endif *ptr = (void *) 0; } } #define WAIT_BUFFER 2048 static char * FAR wait_pointers[WAIT_BUFFER] = {0}, **current_wait_ptr = wait_pointers; /* * wait_new_free: same as new_free() except that free() is postponed. */ void wait_new_free(ptr) char **ptr; { if (*current_wait_ptr) new_free(current_wait_ptr); *current_wait_ptr++ = *ptr; if (current_wait_ptr >= wait_pointers + WAIT_BUFFER) current_wait_ptr = wait_pointers; *ptr = (char *) 0; } /* * reall_free: really free the data if level == 0 */ void really_free(level) int level; { if (level != 0) return; for (current_wait_ptr = wait_pointers; current_wait_ptr < wait_pointers + WAIT_BUFFER; current_wait_ptr++) if (*current_wait_ptr) new_free(current_wait_ptr); current_wait_ptr = wait_pointers; } char * new_realloc(ptr, size) char *ptr; size_t size; { char *new_ptr; #ifdef ALLOC_DEBUG int i; #endif if ((new_ptr = (char *) realloc(ptr, size)) == (char *) 0) { fprintf(stderr, "realloc failed (%d): %s\nIrc Aborted!\n", (int)size, strerror(errno)); exit(1); } #ifdef ALLOC_DEBUG for (i = 0;i < ALLOC_LIST; i++) if ((char *) MemList[i] == ptr) break; if (i == ALLOC_LIST) { fprintf(stderr, "Memory freed that was never allocated"); abort(); } MemList[i] = new_ptr; MemSize[i] = size; #endif return (new_ptr); } char * new_malloc(size) size_t size; { char *ptr; #ifdef ALLOC_DEBUG int i; if (!Init) { Init = 1; for (i = 0; i < ALLOC_LIST; i++) { MemList[i] = (void *) 0; MemSize[i] = 0L; } if (getenv("DEBUG")) (void) MY_SIGNAL(SIGSEGV, dump_mem, 0); } #endif if ((ptr = (char *) malloc(size)) == (char *) 0) { static char error[] = "Malloc failed: \nIrc Aborted!\n"; write(2, error, strlen(error)); write(2, strerror(errno), strlen(strerror(errno))); term_reset(); exit(1); } #ifdef ALLOC_DEBUG for (i = 0; i < ALLOC_LIST && MemList[i]; i++) ; if (i == ALLOC_LIST) { FILE *fp; int j; fprintf(stderr, "Out of space in memory record. Probable memory leak\n"); fp = fopen("debug.log", "w"); for (i = 0; i < ALLOC_LIST; i++) { fprintf(fp, " %08lx %08lx \"", (long) MemList[i], MemSize[i]); for (j = 0; j < MemSize[i] && j < 45; j++) { if (MemList[i][j] < 32 || MemList[i][j] > 127) putc('.', fp); else putc(MemList[i][j], fp); } fprintf(fp, "\"\n"); } fclose(fp); abort(); } MemList[i]=ptr; MemSize[i]=size; #endif return (ptr); } #ifdef ALLOC_DEBUG void alloc_cmd(command, args, subargs) char *command, *args, *subargs; { char *arg; int f_count = 0, f_dump = 0; int i, j; int count; long size; FILE *fp; while ((arg = next_arg(args, &args))) { while (*arg) { switch(*arg++) { case 'c': case 'C': f_count = 1; break; case 'd': case 'D': f_dump = 1; break; } } } if (f_dump) fp = fopen("debug.log", "w"); else fp = NULL; for (size = count = i = 0; i < ALLOC_LIST; i++) { if (fp && MemList[i]) { fprintf(fp, " %08lx %08lx \"", (long) MemList[i], MemSize[i]); for (j = 0; j < MemSize[i] && j < 45; j++) { if (MemList[i][j] < 32 || MemList[i][j] > 127) putc('.', fp); else putc(MemList[i][j], fp); } fprintf(fp, "\"\n"); } if (MemList[i]) { count++; size += MemSize[i]; } } if (fp) fclose(fp); if (f_count) { say("%d blocks allocated out of %d", count, ALLOC_LIST); say("%ld bytes allocated, an average of %ld per block", size, size/count); } } #endif /* * malloc_strcpy: Mallocs enough space for src to be copied in to where * ptr points to. * * Never call this with ptr pointing to an uninitialised string, as the * call to new_free() might crash the client... - phone, jan, 1993. */ void malloc_strcpy(ptr, src) char **ptr; char *src; { /* no point doing anything else */ if (src == *ptr) return; new_free(ptr); if (src) { *ptr = new_malloc(strlen(src) + 1); strcpy(*ptr, src); } else *ptr = (char *) 0; } /* malloc_strcat: Yeah, right */ void malloc_strcat(ptr, src) char **ptr; char *src; { char *new; if (*ptr) { new = (char *) new_malloc(strlen(*ptr) + strlen(src) + 1); strcpy(new, *ptr); strcat(new, src); new_free(ptr); *ptr = new; } else malloc_strcpy(ptr, src); } void malloc_strcat_ue(ptr, src) char **ptr; char *src; { char *new; if (*ptr) { size_t len = strlen(*ptr) + strlen(src) + 1; new = (char *) new_malloc(len); strcpy(new, *ptr); strmcat_ue(new, src, len); new_free(ptr); *ptr = new; } else malloc_strcpy(ptr, src); } char * upper(s) char *s; { /**************************** PATCHED by Flier ******************************/ /*char *t = (char *) 0;*/ register char *t = (char *) 0; /****************************************************************************/ if (s) for (t = s; *s; s++) if (islower(*s)) *s = toupper(*s); return (t); } char * lower(s) char * s; { char * t = (char *) 0; if (s) for (t = s; *s; s++) if (isupper(*s)) *s = tolower(*s); return t; } /**************************** PATCHED by Flier ******************************/ /* try to find unused port in port range given in /set dcc_ports */ int BindPort(s,slisten,localaddr) int s; int slisten; struct sockaddr_in *localaddr; { int sal=sizeof(struct sockaddr_in); int locport; for (locport=DCCLowPort;locport<=DCCHighPort;locport++) { localaddr->sin_port=htons(locport); if (bind(s,(struct sockaddr *) localaddr,sal)==0) { if (slisten && (listen(s,1)==0)) break; else if (!slisten) break; } } if (!(locport>=DCCLowPort && locport<=DCCHighPort)) { new_close(s); say("Could not allocate DCC port in range %d - %d", DCCLowPort,DCCHighPort); return(-4); } return(s); } /****************************************************************************/ /* * Connect_By_Number Performs a connecting to socket 'service' on host * 'host'. Host can be a hostname or ip-address. If 'host' is null, the * local host is assumed. The parameter full_hostname will, on return, * contain the expanded hostname (if possible). Note that full_hostname is a * pointer to a char *, and is allocated by connect_by_numbers() * * The following special values for service exist: * * 0 Create a socket for accepting connections * * -1 Create a UDP socket * * -2 Connect to the address passed in place of the hostname parameter * * Errors: * * -1 get service failed * * -2 get host failed * * -3 socket call failed * * -4 connect call failed */ int /**************************** PATCHED by Flier ******************************/ /*connect_by_number(service, host, nonblocking)*/ connect_by_number(service,host,nonblocking,dccget) /****************************************************************************/ int service; char *host; int nonblocking; /**************************** PATCHED by Flier ******************************/ int dccget; /****************************************************************************/ { int s = -1; char buf[100]; int err = -1; #ifndef INET6 struct sockaddr_in server; struct hostent *hp; #else char strhost[1025], strservice[32]; struct sockaddr_storage server; struct addrinfo hints, *res, *res0; strncpy(strhost, host, sizeof(strhost) - 1); strhost[sizeof(strhost) - 1] = 0; snprintf(strservice, sizeof strservice, "%d", service); strservice[sizeof(strservice) - 1] = 0; #endif if (service == -2) { #ifdef INET6 #ifndef SA_LEN # ifdef HAVE_SOCKADDR_SA_LEN # define SA_LEN(x) (x)->sa_len # else # ifdef SIN6_LEN # define SA_LEN(x) SIN6_LEN(x) # else # ifdef SIN_LEN # define SA_LEN(x) SIN_LEN(x) # else # define SA_LEN(x) sizeof(*x) # endif # endif # endif #endif server = (*(struct sockaddr_storage *) host); getnameinfo((struct sockaddr *)&server, SA_LEN((struct sockaddr *)&server), strhost, sizeof(strhost), strservice, sizeof(strservice), NI_NUMERICHOST|NI_NUMERICSERV); #else server = (*(struct sockaddr_in *) host); #endif } else if (service > 0) { if (host == (char *) 0) { gethostname(buf, sizeof(buf)); host = buf; } #ifndef INET6 if ((server.sin_addr.s_addr = inet_addr(host)) == -1) { if ((hp = gethostbyname(host)) != NULL) { bzero((char *) &server, sizeof(server)); bcopy(hp->h_addr, (char *) &server.sin_addr, (size_t)hp->h_length); server.sin_family = hp->h_addrtype; } else return (-2); } else server.sin_family = AF_INET; server.sin_port = (unsigned short) htons(service); #endif } #ifdef INET6 memset(&hints, 0, sizeof(hints)); if (service == -1) hints.ai_socktype = SOCK_DGRAM; else hints.ai_socktype = SOCK_STREAM; /* If strhost is empty then probably DCC connection was requested. * In this case we must use AF_INET */ errno = 0; if (strlen(strhost) == 0) { hints.ai_family = AF_INET; err = getaddrinfo(NULL, strservice, &hints, &res0); } else { hints.ai_family = AF_UNSPEC; err = getaddrinfo(strhost, strservice, &hints, &res0); } if (err != 0) { #if 0 /* zero errno to get "unknown host" error message */ errno = 0; #endif return (-2); } err = -1; for (res = res0; res; res = res->ai_next) { if ((s = socket(res->ai_family, res->ai_socktype, res->ai_protocol)) < 0) continue; if (service != -1) set_socket_options(s); #else if (((service == -1) && ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0)) || ((service != -1) && ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0))) return (-3); if (service != -1) set_socket_options(s); #endif if (service <= 0 && service != -2) { #ifdef INET6 if (bind_local_addr(NULL, "0", s, res->ai_family) < 0) return -2; freeaddrinfo(res0); if (listen(s, 1) == -1) { new_close(s); return -4; } #else /**************************** PATCHED by Flier ******************************/ int newsock; /****************************************************************************/ struct sockaddr_in localaddr; bzero(&localaddr, sizeof(struct sockaddr_in)); localaddr.sin_family = AF_INET; if (!service) localaddr.sin_addr.s_addr = INADDR_ANY; else localaddr.sin_addr = MyHostAddr; localaddr.sin_port = 0; /**************************** PATCHED by Flier ******************************/ /*if (bind(s, (struct sockaddr *) &localaddr, sizeof(localaddr)) == -1 || (!service && listen(s, 1) == -1)) { new_close(s); return -4; }*/ if (DCCLowPort>1023 && DCCHighPort<65500 && !service) { if ((newsock=BindPort(s,1,&localaddr))<0) return(newsock); } else { if (bind(s,(struct sockaddr *) &localaddr,sizeof(localaddr))==-1 || (!service && listen(s,1)==-1)) { new_close(s); return(-4); } } /****************************************************************************/ service = sizeof(localaddr); getsockname(s, (struct sockaddr *) &localaddr, &service); #endif return (s); } /**************************** PATCHED by Flier ******************************/ #ifndef INET6 if (DCCLowPort>1023 && DCCHighPort<65500 && dccget) { int newsock; struct sockaddr_in localaddr; bzero(&localaddr,sizeof(struct sockaddr_in)); localaddr.sin_family=AF_INET; localaddr.sin_addr = MyHostAddr; if ((newsock=BindPort(s,0,&localaddr))<0) return(newsock); } #endif /****************************************************************************/ if (source_host) { #ifdef INET6 int retcode; if ((retcode = bind_local_addr(MyHostName, "0", s, res->ai_family)) < 0) { /* this fail must be ignored because maybe * res->ai_family != MyHostName's family (ie. hapens in DCC req) */ if (retcode != -10) { freeaddrinfo(res0); return -3; } } #else struct sockaddr_in localaddr; bzero(&localaddr, sizeof localaddr); localaddr.sin_family = AF_INET; localaddr.sin_addr = MyHostAddr; if (bind(s, (struct sockaddr *)&localaddr, sizeof localaddr) == -1) return -3; #endif } #ifdef NON_BLOCKING_CONNECTS if (nonblocking && set_non_blocking(s) < 0) { #ifdef INET6 freeaddrinfo(res0); #endif #ifdef ESIX t_close(s); unmark_socket(s); #endif /* ESIX */ new_close(s); return -4; } #endif /* NON_BLOCKING_CONNECTS */ #ifdef INET6 err = connect(s, res->ai_addr, res->ai_addrlen); #else err = connect(s, (struct sockaddr *) &server, sizeof(server)); #endif if (err < 0) { if (!(errno == EINPROGRESS && nonblocking)) { #ifdef INET6 continue; #endif #ifdef ESIX t_close(s); unmark_socket(s); #endif /* ESIX */ new_close(s); return -4; } #ifdef INET6 err = 0; break; #endif } #ifdef INET6 } /* for () */ if (err < 0) { #ifdef ESIX t_close(s); unmark_socket(s); #endif /* ESIX */ new_close(s); return -4; } #endif return s; } #ifdef INET6 /* * Binds to specified socket, host, port using specified family. * Returns: * 0 if everythins is OK * -2 if host wasn't found * -10 if family type wasn't supported for specified host */ static int bind_local_addr(localhost, localport, fd, family) char *localhost; char *localport; int fd; int family; { struct addrinfo hintsx, *resx, *res0x; int err = -1; memset(&hintsx, 0, sizeof(hintsx)); hintsx.ai_family = family; hintsx.ai_socktype = SOCK_STREAM; hintsx.ai_flags = AI_PASSIVE; err = getaddrinfo(localhost, localport, &hintsx, &res0x); if (err != 0) { /* Dirty little hack here, brought to us by ircII-20030709 damm@yazzy.org */ #ifndef EAI_ADDRFAMILY # ifdef EAI_FAMILY # define EAI_ADDRFAMILY EAI_FAMILY # else # error "no EAI_ADDRFAMILY or EAI_FAMILY" # endif #endif if (err == EAI_ADDRFAMILY) return -10; else return -2; } err = -1; for (resx = res0x; resx; resx = resx->ai_next) { if (bind(fd, resx->ai_addr, resx->ai_addrlen) == 0) { err = 0; break; } } freeaddrinfo(res0x); if (err < 0) return -2; return 0; } #endif char * next_arg(str, new_ptr) char *str, **new_ptr; { char *ptr; if ((ptr = sindex(str, "^ ")) != NULL) { if ((str = index(ptr, ' ')) != NULL) *str++ = (char) 0; else str = empty_string; } else str = empty_string; if (new_ptr) *new_ptr = str; return ptr; } char * new_next_arg(str, new_ptr) char *str, **new_ptr; { char *ptr, *start; if ((ptr = sindex(str, "^ \t")) != NULL) { if (*ptr == '"') { start = ++ptr; while ((str = sindex(ptr, "\"\\")) != NULL) { switch (*str) { case '"': *str++ = '\0'; if (*str == ' ') str++; if (new_ptr) *new_ptr = str; return (start); case '\\': if (*(str + 1) == '"') strcpy(str, str + 1); ptr = str + 1; } } str = empty_string; } else { if ((str = sindex(ptr, " \t")) != NULL) *str++ = '\0'; else str = empty_string; } } else str = empty_string; if (new_ptr) *new_ptr = str; return ptr; } /* my_stricmp: case insensitive version of strcmp */ int my_stricmp(str1, str2) /**************************** PATCHED by Flier ******************************/ /*char *str1, *str2;*/ register char *str1, *str2; /****************************************************************************/ { int xor; if (!str1) return -1; if (!str2) return 1; for (; *str1 || *str2 ; str1++, str2++) { if (!*str1 || !*str2) return (*str1 - *str2); if (isalpha(*str1) && isalpha(*str2)) { xor = *str1 ^ *str2; if (xor != 32 && xor != 0) return (*str1 - *str2); } else { if (*str1 != *str2) return (*str1 - *str2); } } return 0; } /* my_strnicmp: case insensitive version of strncmp */ int my_strnicmp(str1, str2, n) /**************************** PATCHED by Flier ******************************/ /*char *str1, *str2;*/ register char *str1, *str2; /****************************************************************************/ size_t n; { size_t i; int xor; for (i = 0; i < n; i++, str1++, str2++) { if (isalpha(*str1) && isalpha(*str2)) { xor = *str1 ^ *str2; if (xor != 32 && xor != 0) return (*str1 - *str2); } else { if (*str1 != *str2) return (*str1 - *str2); } } return 0; } /* * strmcpy: Well, it's like this, strncpy doesn't append a trailing null if * strlen(str) == maxlen. strmcpy always makes sure there is a trailing null */ void strmcpy(dest, src, maxlen) char *dest, *src; size_t maxlen; { strncpy(dest, src, maxlen); dest[maxlen - 1] = '\0'; } /* * strmcat: like strcat, but truncs the dest string to maxlen (thus the dest * should be able to handle maxlen+1 (for the null)) */ void strmcat(dest, src, maxlen) char *dest, *src; size_t maxlen; { size_t srclen, len; srclen = strlen(src); if ((len = strlen(dest) + srclen) > maxlen) strncat(dest, src, srclen - (len - maxlen)); else strcat(dest, src); } /* * strmcat_ue: like strcat, but truncs the dest string to maxlen (thus the dest * should be able to handle maxlen + 1 (for the null)). Also unescapes * backslashes. */ void strmcat_ue(dest, src, maxlen) char *dest, *src; size_t maxlen; { size_t dstlen; dstlen = strlen(dest); dest += dstlen; maxlen -= dstlen; while (*src && maxlen > 0) { if (*src == '\\') { if (index("npr0", src[1])) *dest++ = '\020'; else if (*(src + 1)) *dest++ = *++src; else *dest++ = '\\'; } else *dest++ = *src; src++; } *dest = '\0'; } /* * scanstr: looks for an occurrence of str in source. If not found, returns * 0. If it is found, returns the position in source (1 being the first * position). Not the best way to handle this, but what the hell */ extern int scanstr(source, str) char *str, *source; { int i, max; size_t len; len = strlen(str); max = strlen(source) - len; for (i = 0; i <= max; i++, source++) { if (!my_strnicmp(source, str, len)) return (i + 1); } return (0); } /* expand_twiddle: expands ~ in pathnames. */ char * expand_twiddle(str) char *str; { char lbuf[BIG_BUFFER_SIZE + 1]; if (*str == '~') { str++; if (*str == '/' || *str == '\0') { strmcpy(lbuf, my_path, BIG_BUFFER_SIZE); strmcat(lbuf, str, BIG_BUFFER_SIZE); } else { char *rest; #ifndef _Windows struct passwd *entry; #endif /* _Windows */ if ((rest = index(str, '/')) != NULL) *rest++ = '\0'; #ifdef _Windows if (GetProfileString("IRC", "StartDir", "", lbuf, BIG_BUFFER_SIZE)) { #else if ((entry = getpwnam(str)) != NULL) { strmcpy(lbuf, entry->pw_dir, BIG_BUFFER_SIZE); #endif /* _Windows */ if (rest) { strmcat(lbuf, "/", BIG_BUFFER_SIZE); strmcat(lbuf, rest, BIG_BUFFER_SIZE); } } else return (char *) NULL; } } else strmcpy(lbuf, str, BIG_BUFFER_SIZE); str = '\0'; malloc_strcpy(&str, lbuf); return (str); } /* blundernet increased the size ... */ #if 0 /* islegal: true if c is a legal nickname char anywhere but first char */ #define islegal(c) ((((c) >= 'A') && ((c) <= '}')) || \ (((c) >= '0') && ((c) <= '9')) || \ ((c) == '-') || ((c) == '_')) /* * check_nickname: checks is a nickname is legal. If the first character is * bad new, null is returned. If the first character is bad, the string is * truncd down to only legal characters and returned * * rewritten, with help from do_nick_name() from the server code (2.8.5), * phone, april 1993. */ char * check_nickname(nick) char *nick; { char *s; if (!nick || *nick == '-' || isdigit(*nick)) return NULL; for (s = nick; *s && (s - nick) < NICKNAME_LEN; s++) if (!islegal(*s) || isspace(*s)) break; *s = '\0'; return *nick ? nick : NULL; } #endif /**************************** PATCHED by Flier ******************************/ /* islegal: true if c is a legal nickname char anywhere but first char */ #define islegal(c) ((((c) >= 'A') && ((c) <= '}')) || \ (((c) >= '0') && ((c) <= '9')) || \ ((c) == '-') || ((c) == '_')) /* * We need this function otherwise bad things happen if you /nick erroneous_nick */ char *check_nickname(nick) char *nick; { char *s; if (!nick || *nick=='-' || *nick<'A' || *nick>'}' || isdigit(*nick)) return(NULL); for (s=nick;*s;s++) if (!islegal(*s) || isspace(*s)) break; *s='\0'; return(*nick?nick:NULL); } /****************************************************************************/ /* * sindex: much like index(), but it looks for a match of any character in * the group, and returns that position. If the first character is a ^, then * this will match the first occurence not in that group. */ char * sindex(string, group) /**************************** PATCHED by Flier ******************************/ /*char *string, *group;*/ register char *string, *group; /****************************************************************************/ { char *ptr; if (!string || !group) return (char *) NULL; if (*group == '^') { group++; for (; *string; string++) { for (ptr = group; *ptr; ptr++) { if (*ptr == *string) break; } if (*ptr == '\0') return string; } } else { for (; *string; string++) { for (ptr = group; *ptr; ptr++) { if (*ptr == *string) return string; } } } return (char *) NULL; } /* * srindex: much like rindex(), but it looks for a match of any character in * the group, and returns that position. If the first character is a ^, then * this will match the first occurence not in that group. */ char * srindex(string, group) /**************************** PATCHED by Flier ******************************/ /*char *string, *group;*/ register char *string, *group; /****************************************************************************/ { char *ptr, *str; if (!string || !group) return (char *) NULL; str = string + strlen(string); if (*group == '^') { group++; for (; str != (string-1); str--) { for (ptr = group; *ptr; ptr++) { if (*ptr == *str) break; } if (*ptr == '\0') return str; } } else { for (; str != (string-1); str--) { for (ptr = group; *ptr; ptr++) { if (*ptr == *str) return str; } } } return (char *) NULL; } /* is_number: returns true if the given string is a number, false otherwise */ int is_number(str) /**************************** PATCHED by Flier ******************************/ /*char *str;*/ register char *str; /****************************************************************************/ { while (*str == ' ') str++; if (*str == '-') str++; if (*str) { for (; *str; str++) { if (!isdigit((*str))) return (0); } return 1; } else return 0; } /* rfgets: exactly like fgets, cept it works backwards through a file! */ char * rfgets(lbuf, size, file) char *lbuf; int size; FILE *file; { char *ptr; off_t pos; if (fseek(file, -2L, 1)) return NULL; do { switch (fgetc(file)) { case EOF: return NULL; case '\n': pos = ftell(file); ptr = fgets(lbuf, size, file); fseek(file, (long)pos, 0); return ptr; } } while (fseek(file, -2L, 1) == 0); rewind(file); pos = 0L; ptr = fgets(lbuf, size, file); fseek(file, (long)pos, 0); return ptr; } /* * path_search: given a file called name, this will search each element of * the given path to locate the file. If found in an element of path, the * full path name of the file is returned in a static string. If not, null * is returned. Path is a colon separated list of directories */ char * path_search(name, path) char *name; char *path; { static char FAR lbuf[BIG_BUFFER_SIZE + 1] = ""; char *ptr, *free_path = (char *) 0; malloc_strcpy(&free_path, path); path = free_path; while (path) { #if defined(__MSDOS__) if ((ptr = index(path, ';')) != NULL) #else if ((ptr = index(path, ':')) != NULL) #endif /* __MSDOS */ *(ptr++) = '\0'; /**************************** PATCHED by Flier ******************************/ /*strcpy(lbuf, empty_string);*/ *lbuf='\0'; /****************************************************************************/ if (path[0] == '~') { strmcat(lbuf, my_path, BIG_BUFFER_SIZE); path++; } strmcat(lbuf, path, BIG_BUFFER_SIZE); strmcat(lbuf, "/", BIG_BUFFER_SIZE); strmcat(lbuf, name, BIG_BUFFER_SIZE); if (access(lbuf, F_OK) == 0) break; path = ptr; } new_free(&free_path); return (path) ? lbuf : (char *) 0; } /* * double_quote: Given a str of text, this will quote any character in the * set stuff with the QUOTE_CHAR. It returns a malloced quoted, null * terminated string */ char * double_quote(str, stuff) char *str; char *stuff; { char lbuf[BIG_BUFFER_SIZE + 1]; char *ptr = NULL; char c; int pos; if (str && stuff) { for (pos = 0; (c = *str); str++) { if (index(stuff, c)) { if (c == '$') lbuf[pos++] = '$'; else lbuf[pos++] = '\\'; } lbuf[pos++] = c; } lbuf[pos] = '\0'; malloc_strcpy(&ptr, lbuf); } else malloc_strcpy(&ptr, str); return ptr; } /* * new_stty: given a string of stty commands sets the tty * via ioctls TCGETA/TCSETA. * * WARNING: if someone of the architectures specified in * #if statement don't work ... please comment out * the relative statement and send a report to * * mez002@cdc835.cdc.polimi.it or * rfac@ghost.unimi.it * * or talk with me on IRC ... (i think is better) * * - Allanon - * */ void new_stty(option) char *option; { #if defined(ESIX) || defined(MIPS_SYSV) struct termio ttyset; ioctl(0, TCGETA, &ttyset); if (strstr(option, "opost")) ttyset.c_oflag |= OPOST; if (strstr(option, "sane")) { ttyset.c_iflag &= ~(IGNBRK | PARMRK | INPCK | INLCR | IGNCR | IUCLC | IXOFF); ttyset.c_lflag &= ~(XCASE | ECHOE | ECHONL | NOFLSH); ttyset.c_oflag &= ~(OLCUC | OCRNL | ONOCR | ONLRET | OFILL | OFDEL | NLDLY | CRDLY | TABDLY | BSDLY | VTDLY | FFDLY); ttyset.c_iflag |= (BRKINT | IGNPAR | ISTRIP | ICRNL | IXON); ttyset.c_lflag |= (ISIG | ICANON | ECHO | ECHOK); ttyset.c_oflag |= (OPOST | ONLCR); ttyset.c_cc[VERASE] = CERASE; ttyset.c_cc[VKILL] = CKILL; ttyset.c_cc[VQUIT] = CQUIT; ttyset.c_cc[VINTR] = CINTR; ttyset.c_cc[VEOF] = CEOF; ttyset.c_cc[VEOL] = CNUL; ttyset.c_cc[VSWTCH] = CNUL; } if (strstr(option, "cooked")) /* cooked == -raw */ { ttyset.c_cflag &= ~CSIZE; ttyset.c_cflag |= PARENB; ttyset.c_iflag |= (BRKINT | IGNPAR | ISTRIP | IXON); ttyset.c_oflag |= OPOST; ttyset.c_lflag |= (ICANON | ISIG); ttyset.c_cc[VEOF] = CEOF; ttyset.c_cc[VEOL] = CNUL; } if (strstr(option, "raw")) { ttyset.c_cflag &= ~(CSIZE | PARENB); ttyset.c_iflag &= ~(-1); ttyset.c_lflag &= ~(ISIG | ICANON | XCASE); ttyset.c_oflag &= ~OPOST; ttyset.c_cflag |= CS8; ttyset.c_cc[VMIN] = 1; ttyset.c_cc[VTIME] = 1; } if (strstr(option, "-echo")) ttyset.c_lflag &= ~ECHO; ioctl(0, TCSETAW, &ttyset); #endif } #ifdef ZCAT /* Here another interesting stuff: * it handle zcat of compressed files * You can manage compressed files in this way: * * IN: char *name, the compressed file FILENAME * OUT: a FILE *, from which read the expanded file * */ FILE * zcat(name) char *name; { FILE *fp; int in[2]; in[0] = -1; in[1] = -1; if (pipe(in)) { say("Unable to start decompression process: %s", strerror(errno)); if(in[0] != -1) { new_close(in[0]); new_close(in[1]); } return(NULL); } switch(fork()) { case -1: say("Unable to start decompression process: %s", strerror(errno)); return(NULL); case 0: (void) MY_SIGNAL(SIGINT, (sigfunc *) SIG_IGN, 0); dup2(in[1], 1); new_close(in[0]); setuid(getuid()); setgid(getgid()); #ifdef ZARGS execlp(ZCAT, ZCAT, ZARGS, name, NULL); #else execlp(ZCAT, ZCAT, name, NULL); #endif exit(0); default: new_close(in[1]); if ((fp = fdopen(in[0], "r")) == (FILE *) 0) { say("Cannot open pipe file descriptor: %s", strerror(errno)); return(NULL); } break; } return(fp); } #endif /*ZCAT*/ #ifdef NEED_INDEX extern char * index(s, c) char *s; char c; { # ifdef HAVE_STRSTR return strstr(s, c); # else int len = strlen(s); for (; len > 0 && c != *s; s++, len--) ; return (len) ? s : (char *) NULL; # endif /* HAVE_STRSTD */ } #endif /* NEED_INDEX */ #ifdef NEED_RINDEX extern char * rindex(s, c) char *s; char c; { # ifdef HAVE_STRRSTR return strrstr(s, c); # else int len = strlen(s); char *t = s; s += len; for (; s >= t && c != *s; s--) ; return (s < t) ? (char *) NULL : s; # endif /* HAVE_STRRSTR */ } #endif /* NEED_RINDEX */ #ifdef NON_BLOCKING_CONNECTS int set_non_blocking(fd) int fd; { int res, nonb = 0; #if defined(NBLOCK_POSIX) nonb |= O_NONBLOCK; #else # if defined(NBLOCK_BSD) nonb |= O_NDELAY; # else # if defined(NBLOCK_SYSV) res = 1; if (ioctl (fd, FIONBIO, &res) < 0) return -1; # else no idea how to set an fd to non-blocking # endif # endif #endif #if (defined(NBLOCK_POSIX) || defined(NBLOCK_BSD)) && !defined(NBLOCK_SYSV) if ((res = fcntl(fd, F_GETFL, 0)) == -1) return -1; else if (fcntl(fd, F_SETFL, res | nonb) == -1) return -1; #endif return 0; } int set_blocking(fd) int fd; { int res, nonb = 0; #if defined(NBLOCK_POSIX) nonb |= O_NONBLOCK; #else # if defined(NBLOCK_BSD) nonb |= O_NDELAY; # else # if defined(NBLOCK_SYSV) res = 0; if (ioctl (fd, FIONBIO, &res) < 0) return -1; # else no idea how to return an fd blocking # endif # endif #endif #if (defined(NBLOCK_POSIX) || defined(NBLOCK_BSD)) && !defined(NBLOCK_SYSV) if ((res = fcntl(fd, F_GETFL, 0)) == -1) return -1; else if (fcntl(fd, F_SETFL, res &~ nonb) == -1) return -1; #endif return 0; } #endif