/* EnergyMech, IRC bot software Parts Copyright (c) 1997-2009 proton 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. */ #define FUNCTION_C #include "config.h" #include "defines.h" #include "structs.h" #include "global.h" #include "h.h" #include "text.h" LS char timebuf[24]; /* max format lentgh == 20+1, round up to nearest longword -> 24 */ LS char idlestr[36]; /* max format lentgh == 24+1, round up to nearest longword -> 28 */ LS const char monlist[12][4] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; LS const char daylist[7][4] = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" }; /* * memory allocation routines */ #ifdef DEBUG __attr(CORE_SEG,__regparm(1)) void *Calloc(int size) { aME *mmep; aMEA *mp; int i; #ifdef __GNUC__ if (mallocdoer == NULL) { mallocdoer = __builtin_return_address(0); debug("(Calloc) mallocdoer = "mx_pfmt"\n",(mx_ptr)mallocdoer); mallocdoer = NULL; } #endif /* GNUC */ mmep = NULL; mp = mrrec; while(!mmep) { for(i=0;imme[i].area == NULL) { mmep = &mp->mme[i]; break; } } if (!mmep) { if (mp->next == NULL) { mp->next = calloc(sizeof(aMEA),1); mmep = &mp->next->mme[0]; } else mp = mp->next; } } /* * heap check +4 bytes */ if ((mmep->area = (void*)calloc(size+4,1)) == NULL) { run_debug(); exit(1); } mmep->size = size; mmep->when = now; mmep->doer = mallocdoer; mallocdoer = NULL; return((void*)mmep->area+4); } __attr(CORE_SEG,__regparm(1)) void Free(char **mem) { aME *mmep; aMEA *mp; int *src; int i; if (*mem == NULL) return; src = (int*)((*mem)-4); mmep = NULL; mp = mrrec; while(!mmep) { for(i=0;imme[i].area == src) { mmep = &mp->mme[i]; break; } } if (!mmep) { if (mp->next == NULL) { debug("(Free) PANIC: Free(0x"mx_pfmt"); Unregistered memory block\n",(mx_ptr)src); run_debug(); exit(1); } mp = mp->next; } } if (*src) debug("Free: Heap corruption at 0x"mx_pfmt"\n",(mx_ptr)(*mem)-4); mmep->area = NULL; mmep->size = 0; mmep->when = (time_t)0; free((*mem)-4); *mem = NULL; } #else /* DEBUG */ __attr(CORE_SEG,__regparm(1)) void *Calloc(int size) { void *tmp; if ((tmp = (void*)calloc(size,1)) == NULL) exit(1); return((void*)tmp); } /* * Free() can be called with NULL's */ __attr(CORE_SEG,__regparm(1)) void Free(char **mem) { if (*mem) { free(*mem); *mem = NULL; } } #endif /* DEBUG */ const int Strlen(const char *first, ...) { const char *s,*o; int n; va_list vlist; va_start(vlist,first); n = 0; o = s = first; do { while(*s) s++; n += (s - o); s = o = va_arg(vlist,const char *); } while(s); va_end(vlist); return(n); } __attr(CORE_SEG,__regparm(2)) const int Strlen2(const char *one, const char *two) { const char *s1,*s2; if (one) for(s1=one;*s1;s1++); if (two) for(s2=two;*s2;s2++); return((s1 - one) + (s2 - two)); } __attr(CORE_SEG,__regparm(2)) char *nickcpy(char *dest, const char *nuh) { char *ret; if (!dest) dest = nick_buf; ret = dest; while(*nuh && (*nuh != '!')) *(dest++) = *(nuh++); *dest = 0; return(ret); } char *getuh(char *nuh) { char *s; s = nuh; while(*s) { if (*s == '!') { nuh = s + 1; /* * We have to grab everything from the first '!' since some * braindamaged ircds allow '!' in the "user" part of the nuh */ break; } s++; } return(nuh); } /* * caller is responsible for: * * src != NULL * *src != NULL * */ char *get_token(char **src, const char *token_sep) { const char *s; char *token = NULL; /* * skip past any token_sep chars in the beginning */ if (0) /* is this legal C? */ a: ++(*src); s = token_sep; while(**src && *s) { if (*(s++) == **src) goto a; } if (token || **src == 0) return(token); token = *src; /* * find the next token_sep char */ do { s = token_sep; do { if (*s == **src) { **src = 0; goto a; } ++s; } while(*s); (*src)++; } while(**src); return(token); } /* * time to string routines */ char *logtime(time_t when) { struct tm *btime; btime = localtime(&when); sprintf(timebuf,"%s %i %i %02i:%02i:%02i", /* max format length: 20+1 */ monlist[btime->tm_mon],btime->tm_mday,btime->tm_year+1900, btime->tm_hour,btime->tm_min,btime->tm_sec); return(timebuf); } char *time2str(time_t when) { struct tm *btime; if (!when) return(NULL); btime = localtime(&when); sprintf(timebuf,"%02i:%02i:%02i %s %02i %i", /* max format length: 20+1 */ btime->tm_hour,btime->tm_min,btime->tm_sec,monlist[btime->tm_mon], btime->tm_mday,btime->tm_year+1900); return(timebuf); } char *time2away(time_t when) { struct tm *btime; char ampm; if (!when) return(NULL); btime = localtime(&when); if (btime->tm_hour < 12) { if (btime->tm_hour == 0) btime->tm_hour = 12; ampm = 'a'; } else { if (btime->tm_hour != 12) btime->tm_hour -= 12; ampm = 'p'; } sprintf(timebuf,"%i:%02i%cm %s %s %i", /* max format length: 18+1 */ btime->tm_hour,btime->tm_min,ampm,daylist[btime->tm_wday], monlist[btime->tm_mon],btime->tm_mday); return(timebuf); } char *time2medium(time_t when) { struct tm *btime; btime = localtime(&when); sprintf(timebuf,"%02i:%02i", /* max format length: 5+1 */ btime->tm_hour,btime->tm_min); return(timebuf); } char *time2small(time_t when) { struct tm *btime; btime = localtime(&when); sprintf(timebuf,"%s %02i", /* max format length: 6+1 */ monlist[btime->tm_mon],btime->tm_mday); return(timebuf); } char *idle2str(time_t when, int small) { char *dst; int n,z[4]; z[0] = when / 86400; z[1] = (when -= z[0] * 86400) / 3600; z[2] = (when -= z[1] * 3600) / 60; z[3] = when % 60; /* 32 : "9999 days, 24 hours, 59 minutes" */ /* xx : "24 hours, 59 minutes" */ /* xx : "59 minutes, 59 seconds" */ /* xx : "59 seconds" */ if (small) { char *f[] = {"day","hour","minute","second"}; *idlestr = 0; for(n=0;n<4;n++) { if (*idlestr || z[n]) { dst = STREND(idlestr); sprintf(dst,"%s%i %s%s",(*idlestr) ? ", " : "",z[n],f[n],(z[n]==1) ? "" : "s"); } } } else /* 18+1 (up to 9999 days) */ sprintf(idlestr,"%i day%s %02i:%02i:%02i",z[0],EXTRA_CHAR(z[0]),z[1],z[2],z[3]); return(idlestr); } __attr(CMD1_SEG,__regparm(2)) char *get_channel(char *to, char **rest) { char *channel; if (*rest && ischannel(*rest)) { channel = chop(rest); } else { if (!ischannel(to) && current->activechan) channel = current->activechan->name; else channel = to; } return(channel); } char *get_channel2(char *to, char **rest) { char *channel; if (*rest && (**rest == '*' || ischannel(*rest))) { channel = chop(rest); } else { if (!ischannel(to) && current->activechan) channel = current->activechan->name; else channel = to; } return(channel); } char *cluster(char *hostname) { char mask[NUHLEN]; char *p,*host; char num,dot; host = p = hostname; num = dot = 0; while(*p) { if (*p == '@') { host = p + 1; num = dot = 0; } else if (*p == '.') dot++; else if (*p < '0' || *p > '9') num++; p++; } if (!num && (dot == 3)) { /* * its a numeric IP address * 1.2.3.4 --> 1.2.*.* */ p = mask; while(*host) { if (*host == '.') { if (num) break; num++; } *(p++) = *(host++); } Strcpy(p,".*.*"); } else { /* * its not a numeric mask */ p = mask; *(p++) = '*'; num = (dot >= 4) ? 2 : 1; while(*host) { if (*host == '.') dot--; if (dot <= num) break; host++; } Strcpy(p,host); } Strcpy(hostname,mask); return(hostname); } /* * type output * ~~~~ ~~~~~~ * 0,1 *!*user@*.host.com * 2 *!*@*.host.com */ char *format_uh(char *userhost, int type) { char tmpmask[NUHLEN]; char *u,*h; if (STRCHR(userhost,'*')) return(userhost); Strcpy(tmpmask,userhost); h = tmpmask; get_token(&h,"!"); /* discard nickname */ u = get_token(&h,"@"); if (*h == 0) return(userhost); if (u && (type < 2)) { if ((type = strlen(u)) > 9) u += (type - 9); else if (*u == '~') u++; } sprintf(userhost,"*!*%s@%s",(u) ? u : "",cluster(h)); return(userhost); } /* * NOTE! beware of conflicts in the use of nuh_buf, its also used by find_nuh() */ char *nick2uh(char *from, char *userhost) { if (STRCHR(userhost,'!') && STRCHR(userhost,'@')) { Strcpy(nuh_buf,userhost); } else if (!STRCHR(userhost,'!') && !STRCHR(userhost,'@')) { /* find_nuh() stores nickuserhost in nuh_buf */ if (find_nuh(userhost) == NULL) { if (from) to_user(from,"No information found for %s",userhost); return(NULL); } } else { Strcpy(nuh_buf,"*!"); if (!STRCHR(userhost,'@')) Strcat(nuh_buf,"*@"); Strcat(nuh_buf,userhost); } return(nuh_buf); } void deop_ban(Chan *chan, ChanUser *victim, char *mask) { if (!mask) mask = format_uh(get_nuh(victim),FUH_USERHOST); send_mode(chan,85,QM_CHANUSER,'-','o',victim); send_mode(chan,90,QM_RAWMODE,'+','b',mask); } void deop_siteban(Chan *chan, ChanUser *victim) { char *mask; mask = format_uh(get_nuh(victim),FUH_HOST); deop_ban(chan,victim,mask); } void screwban_format(char *userhost) { int sz,n,pos; #ifdef DEBUG debug("(screwban_format) %s\n",userhost); #endif /* DEBUG */ if ((sz = strlen(userhost)) < 8) return; n = RANDOM(4,sz); while(--n) { pos = RANDOM(0,(sz - 1)); if (!STRCHR("?!@*",userhost[pos])) { userhost[pos] = (RANDOM(0,3) == 0) ? '*' : '?'; } } } void deop_screwban(Chan *chan, ChanUser *victim) { char *mask; int i; for(i=2;--i;) { mask = format_uh(get_nuh(victim),FUH_USERHOST); screwban_format(mask); deop_ban(chan,victim,mask); } } int is_nick(const char *nick) { uchar *p; p = (uchar*)nick; if ((attrtab[*p] & FNICK) != FNICK) return(FALSE); while(*p) { if ((attrtab[*p] & NICK) != NICK) return(FALSE); p++; } return(TRUE); } int capslevel(char *text) { int sz,upper; if (!*text) return(0); sz = upper = 0; while(*text) { if ((*text >= 'A' && *text <= 'Z') || (*text == '!')) upper++; sz++; text++; } sz = sz / 2; return(upper >= sz); } __attr(CORE_SEG,__regparm(1)) int a2i(char *anum) { int res = 0,neg; errno = EINVAL; if (!anum || !*anum) return(-1); neg = (*anum == '-') ? 1 : 0; anum += neg; while(*anum) { if (0 == (attrtab[(uchar)*anum] & NUM)) return(-1); res = (res * 10) + *(anum++) - '0'; } errno = 0; return((neg) ? -res : res); } int get_number(const char *rest) { const char *src = NULL; int n = 0; while(*rest) { if (*rest >= '0' && *rest <= '9') n = (n * 10) + (*(src = rest) - '0'); else if (src) return(n); rest++; } return(n); } __attr(CORE_SEG,__regparm(1)) void fix_config_line(char *text) { char *s,*space; space = NULL; for(s=text;*s;s++) { if (*s == '\t') *s = ' '; if (!space && *s == ' ') space = s; if (space && *s != ' ') space = NULL; } if (space) *space = 0; } /* * returns NULL or non-zero length string */ __attr(CORE_SEG,__regparm(1)) char *chop(char **src) { char *tok,*cut = *src; while(*cut && *cut == ' ') cut++; if (*cut) { tok = cut; while(*cut && *cut != ' ') cut++; *src = cut; while(*cut && *cut == ' ') cut++; **src = 0; *src = cut; } else { tok = NULL; } return(tok); } /* * remove all '\0' in an array bounded by two pointers */ __attr(CORE_SEG,__regparm(2)) void unchop(char *orig, char *rest) { for(;orig orig));m--) ; if ((*m == '*') && (m > orig) && (m[-1] != '\\')) return(FALSE); if (wild) { m = (uchar *)mask; n = (uchar *)++text; } else return(TRUE); } else if (!*n) { while(*m == '*') m++; return(*m != 0); } if (*m == '*') { while (*m == '*') m++; wild = 1; mask = (char *)m; text = (char *)n; } if ((*m == '\\') && ((m[1] == '*') || (m[1] == '?'))) { m++; q = 1; } else q = 0; if ((tolowertab[(uchar)*m] != tolowertab[(uchar)*n]) && ((*m != '?') || q)) { if (wild) { m = (uchar *)mask; n = (uchar *)++text; } else return(TRUE); } else { if (*m) m++; if (*n) n++; } goto loop; } __att2(CORE_SEG,const,__regparm(2)) int num_matches(const char *mask, const char *text) { const char *p = mask; int n; n = !matches(mask,text); if (n) { do { if (*p != '*') n++; } while(*++p); } return(n); } Strp *e_table = NULL; void table_buffer(const char *format, ...) { Strp **sp; va_list msg; int sz; va_start(msg,format); sz = sizeof(Strp) + vsprintf(gsockdata,format,msg); va_end(msg); for(sp=&e_table;*sp;sp=&(*sp)->next) ; set_mallocdoer(table_buffer); *sp = (Strp*)Calloc(sz); /* Calloc sets to zero (*sp)->next = NULL; */ Strcpy((*sp)->p,gsockdata); } __attr(CMD1_SEG, __regparm (2) ) void table_send(const char *from, const int space) { char message[MAXLEN]; Strp *sp,*next; char *src,*o,*end; int i,u,g,x,z[6]; z[0] = z[1] = z[2] = z[3] = z[4] = z[5] = 0; for(sp=e_table;sp;sp=sp->next) { u = i = 0; src = o = sp->p; while(*src) { if (*src == '\037' || *src == '\002') u++; if (*src == '\t' || *src == '\r') { x = (src - o) - u; if (x > z[i]) z[i] = x; i++; o = src+1; u = 0; } src++; } } for(sp=e_table;sp;sp=next) { next = sp->next; o = message; src = sp->p; g = x = i = 0; while(*src) { if (g) { end = src; while(*end && *end != '\t' && *end != '\r') end++; g -= (end - src); while(g-- > 0) *(o++) = ' '; } if (*src == '\037' || *src == '\002') x++; if (*src == '\t' || *src == '\r') { if (*src == '\r') g = z[i+1]; src++; x += (z[i++] + space); while(o < (message + x)) *(o++) = ' '; } else *(o++) = *(src++); } *o = 0; to_user(from,FMT_PLAIN,message); Free((char**)&sp); } e_table = NULL; } int is_safepath(const char *path) { struct stat st; ino_t ino; char tmp[PATH_MAX]; const char *src; char *dst; int path_token_check(void) { *dst = 0; lstat(tmp,&st); if (!(S_ISREG(st.st_mode) || S_ISDIR(st.st_mode))) return(FALSE); if (st.st_ino == parent_inode) return(FALSE); return(S_ISDIR(st.st_mode) ? 2 : 1); } if (*(src = path) == '/') return(FALSE); dst = tmp; while(*src) { if (*src == '/' && !path_token_check()) return(FALSE); if (dst == tmp + PATH_MAX-1) return(FALSE); *dst++ = *src++; } return(path_token_check() == 1 ? TRUE : FALSE); }