int kill_message (const char *from, const char *cline) { char *poor_sap; char *bastard; const char *path_to_bastard; char *reason; char *line; line = LOCAL_COPY(cline); poor_sap = next_arg(line, &line); /* Dalnet kill BBC and doesnt append the period */ if (!end_strcmp(poor_sap, ".", 1)) chop(poor_sap, 1); /* dalnet kill BBC and doesnt use "From", but "from" */ if (my_strnicmp(line, "From ", 5)) { yell("Attempted to parse an ill-formed KILL request [%s %s]", poor_sap, line); return 0; } line += 5; bastard = next_arg(line, &line); /* Hybrid BBC and doesn't include the kill-path. */ /* Fend off future BBC kills */ if (my_strnicmp(line, "Path: ", 6)) { path_to_bastard = "*"; reason = line; /* Hope for the best */ } else { line += 6; path_to_bastard = next_arg(line, &line); reason = line; } return !do_hook(KILL_LIST, "%s %s %s %s %s", from, poor_sap, bastard, path_to_bastard, reason); }
/* * NAME: connectory * USAGE: Connect to a given "host" and "port" with the given "family" * ARGS: family - AF_INET is the only supported argument. * host - A hostname or "dotted quad" (or equivalent). * port - The remote port to connect to in *HOST ORDER*. * * XXX - This so violates everything I really wanted this function to be, * but I changed it to call getaddrinfo() directly instead of calling * inet_vhostsockaddr() because I wanted it to be able to take advantage * of connecting to multiple protocols and multiple ip addresses (for things * like ``us.undernet.org'') without having to do multiple calls to * getaddrinfo() which could be quite costly. */ int connectory (int family, const char *host, const char *port) { AI hints, *results, *ai; int err; int fd; SS localaddr; socklen_t locallen; memset(&hints, 0, sizeof(hints)); hints.ai_family = family; hints.ai_socktype = SOCK_STREAM; if ((err = Getaddrinfo(host, port, &hints, &results))) { yell("Hostname lookup for [%s:%s] failed: %s (%d)", host, port, gai_strerror(err), err); return -5; } fd = -1; for (ai = results; ai; ai = ai->ai_next) { /* First, look up the virtual host we use for this protocol. */ err = inet_vhostsockaddr(ai->ai_family, -1, &localaddr, &locallen); if (err < 0) continue; /* Now try to do the connection. */ fd = client_connect((SA *)&localaddr, locallen, ai->ai_addr, ai->ai_addrlen); if (fd < 0) { err = fd; fd = -1; continue; } else break; } Freeaddrinfo(results); if (fd < 0) return err; return fd; }
void whilecmd(u_char *command, u_char *args, u_char *subargs) { u_char *expr = NULL, *ptr, *body = NULL, *newexp = NULL; int args_used; /* this isn't used here, but is passed * to expand_alias() */ if ((ptr = next_expr(&args, '(')) == NULL) { yell("WHILE: missing boolean expression"); return; } malloc_strcpy(&expr, ptr); if ((ptr = next_expr(&args, '{')) == NULL) { say("WHILE: missing expression"); new_free(&expr); return; } malloc_strcpy(&body, ptr); while (1) { malloc_strcpy(&newexp, expr); ptr = parse_inline(newexp, subargs ? subargs : empty_string(), &args_used); if (*ptr && *ptr !='0') { new_free(&ptr); parse_line(NULL, body, subargs ? subargs : empty_string(), 0, 0, 0); } else break; } new_free(&newexp); new_free(&ptr); new_free(&expr); new_free(&body); }
/* * NAME: inet_strton * USAGE: Convert "any" kind of address represented by a string into * a socket address suitable for connect()ing or bind()ing with. * ARGS: hostname - The address to convert. It may be any of the following: * IPv4 "Presentation Address" (A.B.C.D) * IPv6 "Presentation Address" (A:B::C:D) * Hostname (foo.bar.com) * 32 bit host order ipv4 address (2134546324) * storage - A pointer to a (struct sockaddr_storage) with the * "family" argument filled in (AF_INET or AF_INET6). * If "hostname" is a p-addr, then the form of the p-addr * must agree with the family in 'storage'. */ int inet_strton (const char *host, const char *port, SA *storage, int flags) { int family = storage->sa_family; /* First check for legacy 32 bit integer DCC addresses */ if ((family == AF_INET || family == AF_UNSPEC) && host && is_number(host)) { ((ISA *)storage)->sin_family = AF_INET; #ifdef HAVE_SA_LEN ((ISA *)storage)->sin_len = sizeof(ISA); #endif ((ISA *)storage)->sin_addr.s_addr = htonl(strtoul(host, NULL, 10)); if (port) ((ISA *)storage)->sin_port = htons((unsigned short)strtoul(port, NULL, 10)); return 0; } else { AI hints; AI *results; int retval; memset(&hints, 0, sizeof(hints)); hints.ai_flags = flags; hints.ai_family = family; hints.ai_socktype = SOCK_STREAM; hints.ai_protocol = 0; if ((retval = Getaddrinfo(host, port, &hints, &results))) { yell("getaddrinfo(%s): %s", host, gai_strerror(retval)); return -5; } /* memcpy can bite me. */ memcpy(storage, results->ai_addr, results->ai_addrlen); Freeaddrinfo(results); return 0; } return -2; }
static int open_dbm (const char *filename, int rdonly, int type) { SDBM *db; Dbm *dbm; int perm; if (rdonly) perm = O_RDONLY; else perm = O_RDWR|O_CREAT; if (!(db = sdbm_open(filename, perm, 0660))) { yell("open_dbm(%s) failed: %s", filename, strerror(errno)); return -1; } dbm = new_dbm(db, type); return dbm->refnum; }
static time_t convert_note_time_to_real_time(char *stuff) { time_t days = 0, hours = 0, minutes = 0; stuff++; /* first character is a '/' */ days = strtoul(stuff, &stuff, 10); /* get the number of days */ stuff++; /* skip over the 'd' */ stuff++; /* skip over the ':' */ hours = strtoul(stuff, &stuff, 10); /* get the number of hours */ stuff++; /* skip over the 'h' */ stuff++; /* skip over the ':' */ minutes = strtoul(stuff, &stuff, 10); /* get the number of minutes */ stuff++; /* skip over the 'm' */ stuff++; /* skip over the '/' */ if (*stuff) yell("cntto: bad format"); hours += days * 24; minutes += hours * 60; return (time(NULL) - minutes * 60); }
/* * kill_process: sends the given signal to the specified process. It does * not delete the process from the process table or anything like that, it * only is for sending a signal to a sub process (most likely in an attempt * to kill it.) The actual reaping of the children will take place async * on the next parsing run. */ static void kill_process (int kill_index, int sig) { pid_t pgid; if (!process_list || kill_index > process_list_size || !process_list[kill_index]) { say("There is no such process %d", kill_index); return; } say("Sending signal %s (%d) to process %d: %s", sys_siglist[sig], sig, kill_index, process_list[kill_index]->name); #ifdef HAVE_GETPGID pgid = getpgid(process_list[kill_index]->pid); #else # ifndef GETPGRP_VOID pgid = getpgrp(process_list[kill_index]->pid); # else pgid = process_list[kill_index]->pid; # endif #endif #ifndef HAVE_KILLPG # define killpg(pg, sig) kill(-(pg), (sig)) #endif /* The exec'd process shouldn't be in our process group */ if (pgid == getpid()) { yell("--- exec'd process is in my job control session! Something is hosed ---"); return; } killpg(pgid, sig); kill(process_list[kill_index]->pid, sig); }
void FormMain::countFolders( int folder_id, int & count ) const { QSqlQuery q; q.prepare("SELECT " "id " "FROM " "folders " "WHERE " "parent_id = :id"); q.bindValue(":id", folder_id ); if ( q.exec() ) { while ( q.next() ) { ++count; if ( actionInfoDeep->isChecked() ) countFolders( q.value( 0 ).toInt(), count ); // recursion } } else emit yell( q.lastError().text() ); }
int set_blocking (int fd) { int flag, rval; #if defined(O_NONBLOCK) flag = O_NONBLOCK; #elif defined(O_NDELAY) flag = O_NDELAY; #elif defined(FIONBIO) flag = 0; #else yell("Sorry! Can't set nonblocking on this system!"); #endif #if defined(O_NONBLOCK) || defined(O_NDELAY) if ((rval = fcntl(fd, F_GETFL, 0)) == -1) { syserr(-1, "set_blocking: fcntl(%d, F_GETFL) failed: %s", fd, strerror(errno)); return -1; } if (fcntl(fd, F_SETFL, rval & ~flag) == -1) { syserr(-1, "set_blocking: fcntl(%d, F_SETFL) failed: %s", fd, strerror(errno)); return -1; } #else if (ioctl(fd, FIONBIO, &flag) < 0) { syserr(-1, "set_blocking: ioctl(%d, FIONBIO) failed: %s", fd, strerror(errno)); return -1; } #endif return 0; }
/* * text_to_process: sends the given text to the given process. If the given * process index is not valid, an error is reported and 1 is returned. * Otherwise 0 is returned. * Added show, to remove some bad recursion, phone, april 1993 */ int text_to_process (int proc_index, const char *text, int show) { Process *proc; char * my_buffer; size_t size; char logical_name[1024]; const char *recoded_text; char * extra = NULL; if (valid_process_index(proc_index) == 0) return 1; proc = process_list[proc_index]; if (show) { int l = message_setall(proc->refnum, NULL, LEVEL_OTHER); put_it("%s%s", get_prompt_by_refnum(proc->refnum), text); pop_message_from(l); } size = strlen(text) + 2; my_buffer = alloca(size); snprintf(my_buffer, size, "%s\n", text); index_to_target(proc_index, logical_name, sizeof(logical_name)); recoded_text = outbound_recode(logical_name, proc->server, my_buffer, &extra); if (write(proc->p_stdin, recoded_text, strlen(recoded_text)) <= 0) { yell("Was unable to write text %s to process %d", text, proc_index); } new_free(&extra); set_prompt_by_refnum(proc->refnum, empty_string); return (0); }
void FormMain::dbGetFolder( int parent_id, QTreeWidgetItem * parent ) { QSqlQuery q; q.prepare("SELECT " "name, " "id " "FROM " "folders " "WHERE " "parent_id = :pid " "ORDER BY " "id"); q.bindValue( ":id", parent_id ); if ( q.exec() ) { while ( q.next() ) { const int folder_id = q.value( 1 ).toInt(); QTreeWidgetItem * item = new QTreeWidgetItem(); item->setIcon( 0, QIcon(":/blue.png") ); item->setText( 0, q.value( 0 ).toString() ); item->setData( 0, Qt::UserRole, folder_id ); dbGetFolder( folder_id, item ); if ( parent ) parent->addChild( item ); else tree->addTopLevelItem( item ); } } else emit yell( q.lastError().text() ); }
/* * crypt_msg: Given plaintext 'str', constructs a body suitable for sending * via PRIVMSG or DCC CHAT. */ char *crypt_msg (char *str, Crypt *key) { char buffer[CRYPT_BUFFER_SIZE + 1]; char thing[6]; char *ptr; snprintf(thing, 6, "%cSED ", CTCP_DELIM_CHAR); *buffer = 0; if ((ptr = do_crypt(str, key, 1))) { if (!*ptr) { yell("WARNING: Empty encrypted message, but message " "sent anyway. Bug?"); } strlcat(buffer, thing, sizeof buffer); strlcat(buffer, ptr, sizeof buffer); strlcat(buffer, CTCP_DELIM_STR, sizeof buffer); new_free(&ptr); } else strlcat(buffer, str, sizeof buffer); return malloc_strdup(buffer); }
void FormMain::openInFileManager() { QTreeWidgetItem * item = tree->currentItem(); if ( ! item ) return; int folder_id = item->data( 0, Qt::UserRole ).toInt(); QSqlQuery q; q.prepare("SELECT " "path " "FROM " "folders " "WHERE " "id = :id"); q.bindValue(":id", folder_id ); if ( q.exec() ) { if ( q.first() ) { const QStringList params = QStringList() << QDir::toNativeSeparators( q.value( 0 ).toString() ); #ifdef Q_OS_WIN32 QProcess::startDetached( "explorer.exe", params ); #else QProcess::startDetached( "xdg-open", params ); #endif } } else { emit yell( q.lastError().text() ); } }
static FILE * open_log (const char *logfile, FILE **fp) { char * tempname; size_t templen; Filename fullname; /* If the user hasn't specified a logfile, do nothing */ if (!logfile) return NULL; /* If the user is already logging here, tell them. */ if (*fp) { say("Logging is already on"); return *fp; } /* If necessary, remove "s on the outside of the filename */ /* I do this way too much on accident; it's annoying not to have it */ tempname = LOCAL_COPY(logfile); templen = strlen(tempname); if (templen > 2 && tempname[0] == '"' && tempname[templen - 1] == '"') { tempname[templen - 1] = 0; tempname++; } /* If the result is an empty filename then just punt */ if (!tempname || !*tempname) { yell("Cannot log to the filename [%s] because the result " "was an empty filename", logfile); return NULL; } if (normalize_filename(tempname, fullname)) { yell("Warning: I could not normalize the filename [%s] " "(the result was [%s] -- watch out", logfile, fullname); (void)0; /* Do nothing... */ } if ((*fp = fopen(fullname, "a")) != NULL) { time_t t; struct tm * ltime; char timestr[256]; /* Convert the time to a string to insert in the file */ time(&t); ltime = localtime(&t); /* Not gmtime, m'kay? */ strftime(timestr, 255, "%a %b %d %H:%M:%S %Y", ltime); chmod(fullname, S_IREAD | S_IWRITE); say("Starting logfile %s", fullname); fprintf(*fp, "IRC log started %s\n", timestr); fflush(*fp); } else { yell("Couldn't open logfile %s: %s", fullname, strerror(errno)); *fp = NULL; } return (*fp); }
int main() { int a = 0; printf("%d %d",a,yell(2)); return 0; }
/* I suppose someone could make a case that since the * foreach_handler() routine weeds out any for command that doesnt have * two commands, that checking for those 2 commas is a waste. I suppose. */ void forcmd(u_char *command, u_char *args, u_char *subargs) { u_char *working = NULL; u_char *commence = NULL; u_char *evaluation = NULL; u_char *lameeval = NULL; u_char *iteration = NULL; u_char *sa = NULL; int argsused = 0; u_char *line = NULL; u_char *commands = NULL; /* Get the whole () thing */ if ((working = next_expr(&args, '(')) == NULL) /* ) */ { yell("FOR: missing closing parenthesis"); return; } malloc_strcpy(&commence, working); /* Find the beginning of the second expression */ evaluation = my_index(commence, ','); if (!evaluation) { yell("FOR: no components!"); new_free(&commence); return; } do *evaluation++ = '\0'; while (isspace(*evaluation)); /* Find the beginning of the third expression */ iteration = my_index(evaluation, ','); if (!iteration) { yell("FOR: Only two components!"); new_free(&commence); return; } do { *iteration++ = '\0'; } while (isspace(*iteration)); working = args; while (isspace(*working)) *working++ = '\0'; if ((working = next_expr(&working, '{')) == NULL) /* } */ { yell("FOR: badly formed commands"); new_free(&commence); return; } malloc_strcpy(&commands, working); sa = subargs ? subargs : empty_string(); parse_line(NULL, commence, sa, 0, 0, 0); while (1) { malloc_strcpy(&lameeval, evaluation); line = parse_inline(lameeval, sa, &argsused); if (*line && *line != '0') { new_free(&line); parse_line(NULL, commands, sa, 0, 0, 0); parse_line(NULL, iteration, sa, 0, 0, 0); } else break; } new_free(&line); new_free(&lameeval); new_free(&commence); new_free(&commands); }
int new_match (const char *pattern, const char *string) { int count = 1; int asterisk = 0; int percent = 0; const char *last_asterisk_point = NULL; const char *last_percent_point = NULL; int last_asterisk_count = 0; int last_percent_count = 0; const char *after_wildcard = NULL; int sanity = 0; const char *old_pattern = pattern, *old_string = string; if (x_debug & DEBUG_REGEX_DEBUG) yell("Matching [%s] against [%s]", pattern, string); for (;;) { if (sanity++ > 100000) { yell("Infinite loop in match! pattern = [%s] string = [%s]", old_pattern, old_string); return 0; } /* * If the last character in the pattern was a *, then * we walk the string until we find the next instance int * string, of the character that was after the *. * If we get to the end of string, then obviously there * is no match. A * at the end of the pattern is handled * especially, so we dont need to consider that. */ if (asterisk) { /* * More pattern, no source. Obviously this * asterisk isnt going to cut it. Try again. * This replaces an 'always failure' case. * In 99% of the cases, we will try again and it * will fail anyhow, but 1% of the cases it would * have succeeded, so we need that retry. */ if (!*string) return 0; /* * XXXX Skip over any backslashes... */ if (*pattern == '\\') { pattern++; if (tolower((unsigned char)*string) != tolower((unsigned char)*pattern)) continue; } /* * If the character in the pattern immediately * following the asterisk is a qmark, then we * save where we're at and we allow the ? to be * matched. If we find it doesnt work later on, * then we will come back to here and try again. * OR * We've found the character we're looking for! * Save some state information about how to recover * if we dont match */ else if (*pattern == '?' || (tolower((unsigned char)*string) == tolower((unsigned char)*pattern))) { asterisk = 0; last_asterisk_point = string; last_asterisk_count = count; } /* * This is not the character we're looking for. */ else string++; continue; } /* * Ok. If we're dealing with a percent, but not a asterisk, * then we need to look for the character after the percent. * BUT, if we find a space, then we stop anyways. */ if (percent) { /* * Ran out of string. If there is more to the * pattern, then we failed. Otherwise if the % * was at the end of the pattern, we havent found * a space, so it succeeds! */ if (!*string) { if (*pattern) return 0; else return count; } /* * XXXX Skip over any backslashes... */ if (*pattern == '\\') { pattern++; if (tolower((unsigned char)*string) != tolower((unsigned char)*pattern)) continue; } /* * If we find a space, then we stop looking at the * percent. We're definitely done with it. We also * go back to normal parsing mode, presumably with * the space after the %. */ if (*string == ' ') { percent = 0; last_percent_point = NULL; } /* * If this is not the char we're looking for, then * keep looking. */ else if (tolower((unsigned char)*string) != tolower((unsigned char)*pattern)) string++; /* * We found it! Huzzah! */ else { percent = 0; last_percent_point = string; last_percent_count = count; } continue; } /* * Ok. So at this point, we know we're not handling an * outstanding asterisk or percent request. So we look * to see what the next char is in the pattern and deal * with it. */ switch (*pattern) { /* * If its an asterisk, then we just keep some info about * where we're at. */ case ('*') : case ('%') : { asterisk = 0, percent = 0; do { if (*pattern == '*') asterisk = 1; pattern++; } while (*pattern == '*' || *pattern == '%'); after_wildcard = pattern; if (asterisk) { last_asterisk_point = string; last_asterisk_count = count; } else { percent = 1; last_percent_point = string; last_percent_count = count; } /* * If there's nothing in the pattern after the * asterisk, then it slurps up the rest of string, * and we're definitely done! */ if (asterisk && !*pattern) return count; break; } /* * If its a question mark, then we have to slurp up one * character from the pattern and the string. */ case ('?') : { pattern++; /* * If there is nothing left in string, then we * definitely fail. */ if (!*string) return 0; string++; break; } /* * De-quote any \'s in the pattern. */ case ('\\') : { /* * ircII says that a single \ at the end of a pattern * is defined as a failure. (must quote SOMETHING) */ pattern++; if (!*pattern) return 0; /* * Check to see if the dequoted character and * the next string character are the same. */ if (tolower((unsigned char)*pattern) != tolower((unsigned char)*string)) return 0; count++, string++, pattern++; break; } /* * If there is nothing left in the pattern and string, * then we've definitely succeeded. Return the number of * non-wildcard characters. */ default: { if (!*pattern && !*string) return count; /* * There are regular characters next in the pattern * and string. Are they the same? If they are, walk * past them and go to the next character. */ if (tolower((unsigned char)*pattern) == tolower((unsigned char)*string)) { count++, pattern++, string++; } /* * The two characters are not the same. If we're * currently trying to match a wildcard, go back to * where we started after the wildcard and try looking * again from there. If we are not currently matching * a wildcard, then the entire match definitely fails. */ else if (last_asterisk_point) { asterisk = 1; string = last_asterisk_point + 1; pattern = after_wildcard; count = last_asterisk_count; } else if (last_percent_point) { percent = 1; string = last_percent_point + 1; pattern = after_wildcard; count = last_percent_count; } else return 0; break; } } } return 0; }
/* * 'move_to_prev_word': Move a "mark" from its current position to the * beginning of the "previous" word. * * Arguments: * 'str' - a pointer to a character pointer -- The initial value is the * "mark", and it will be changed upon return to the beginning * of the previous word. * 'start' - The start of the string that (*str) points to. * 'extended' - Whether double quoted words shall be supported * 'delims' - The types of double quoets to honor (if applicable) * * Return value: * If (*str) points to 'start' or is NULL (there is no previous word) * the return value is 0. * Otherwise, the return value is 1. * * Notes: * Regardless of whether 'start' is actually the start of the string that * '*str' points to, this function will treat it as such and will never go * backwards further than 'start'. * If (*str) points to the nul that terminates 'start', then (*str) shall * be set to the first character in the last word in 'start'. * If (*str) points to the first character in any word, then (*str) shall * be set to the first character in the full word BEFORE (*str). * If (*str) points to the middle of a string, then (*str) shall be set to * the first character IN THAT WORD (*str) points to. * If (*str) points to a space, then (*str) shall be set to the first * character in the word before the space. * A "word" always begins on the second character after the end of a word * because the first character after a word is a space (which is reserved * because we might want to change it to a nul). That means if there is * more than one space between words, the first space belongs to the "left" * word and all the rest of the spaces belong to the "right" word! * * XXX - The debugging printfs are ugly. */ static int move_to_prev_word (const char **str, const char *start, int extended, const char *delims) { char what; int simple; const char *pos; if (!str || *str <= start) return 0; /* Overhead -- work out if "" support will be cheap or expensive */ if (delims && delims[0] && delims[1] == 0) { if (x_debug & DEBUG_EXTRACTW_DEBUG) yell(".... move_to_prev_word: Simple processing"); simple = 1; what = delims[0]; } else { if (x_debug & DEBUG_EXTRACTW_DEBUG) yell(".... move_to_prev_word: Expensive processing"); simple = 0; what = 255; } /* Overhead -- work out if we're doing "" support or not. */ CHECK_EXTENDED_SUPPORT /* Start at the mark the user provided us */ pos = *str; if (x_debug & DEBUG_EXTRACTW_DEBUG) yell(".... move_to_prev_word: Starting at [%s] (in [%s])", pos, start); /* * XXX This is a hack, but what do i care? * If we are pointing at the start of a string, then * we want to go to the PREVIOUS word, so cheat by * stepping off the word. This means if you want the * last word, you need to point to the nul, not the last * character before the nul! */ if (pos > start && isspace(pos[-1])) pos--; /* * Skip over whitespace */ while (pos >= start && ((*pos == 0) || my_isspace(*pos))) pos--; /* * In the above 'mark1' case (the normal case), we would be pointing * at the last character in 'two'. If this were a double quoted word * then this would be a double quote of some sort, and this code * checks for that. If it finds a double quote, then it moves to the * "matching" double quote. */ if (pos > start && extended == DWORD_YES && ( (simple == 1 && *pos == what) || (simple == 0 && strchr(delims, *pos)) ) ) { const char * before; if (x_debug & DEBUG_EXTRACTW_DEBUG) yell(".... move_to_prev_word: Handling extended word."); if (!(before = find_backward_quote(pos, start, delims))) panic("find_backward returned NULL [2]"); if (x_debug & DEBUG_EXTRACTW_DEBUG) yell(".... move_to_prev_word: Extended word begins at [%s] (of [%s])", before, start); /* * "Before" either points at a double quote or it points * at the start of the string. If it points at a double * quote, move back one position so it points at a space. */ if (before > start) before--; /* So our new mark is the space before the double quoted word */ pos = before; if (x_debug & DEBUG_EXTRACTW_DEBUG) yell(".... move_to_prev_word: So the position before the extended word is [%s] (of [%s])", pos, start); } /* * If this is not a double quoted word, keep moving backwards until * we find a space -- so our new mark is the space before the start * of the word. */ else { if (x_debug & DEBUG_EXTRACTW_DEBUG) yell(".... move_to_prev_word: Handling simple word."); while (pos >= start && !my_isspace(*pos)) pos--; if (x_debug & DEBUG_EXTRACTW_DEBUG) yell(".... move_to_prev_word: So the position before the simple word is [%s] (of [%s])", pos, start); } /* * If we hit the front of the string (*gulp*), set the return value * (*str) to the start of the string and just punt right here. */ if (pos <= start) { if (x_debug & DEBUG_EXTRACTW_DEBUG) yell(".... move_to_prev_word: Ooops. we hit the start " "of the string. Stopping here."); *str = start; return 1; } /* * Slurp up spaces. */ else { while (*pos && isspace(*pos)) pos++; while (pos > start && isspace(pos[0]) && isspace(pos[-1])) pos--; } if (x_debug & DEBUG_EXTRACTW_DEBUG) yell(".... move_to_prev_word: And after we're done, [%s] is " "the start of the previous word!", pos); *str = pos; return 1; }
void fe(u_char *command, u_char *args, u_char *subargs) { u_char *list = NULL, *templist = NULL, *placeholder, *oldlist = NULL, *sa, *vars, *var[255], *word = NULL, *todo = NULL; int ind, x, y, count, args_flag; unsigned display; for (x = 0; x < 255; var[x++] = NULL) ; list = next_expr(&args, '('); /* ) */ if (!list) { yell ("FE: Missing List for /FE"); return; } sa = subargs ? subargs : (u_char *) " "; malloc_strcpy(&templist, list); do { malloc_strcpy(&oldlist, templist); new_free(&templist); templist = expand_alias(NULL, oldlist, sa, &args_flag, NULL); } while (my_strcmp(templist, oldlist)); new_free(&oldlist); if (*templist == '\0') { new_free(&templist); return; } vars = args; if (!(args = my_index(args, '{'))) /* } */ { yell ("FE: Missing commands"); new_free(&templist); return; } *(args-1) = '\0'; ind = 0; while ((var[ind++] = next_arg(vars, &vars))) { if (ind == 255) { yell ("FE: Too many variables"); new_free(&templist); return; } } ind = ind ? ind - 1: 0; if (!(todo = next_expr(&args, '{'))) /* } { */ { yell ("FE: Missing }"); new_free(&templist); return; } count = word_count(templist); display = get_display(); placeholder = templist; for (x = 0; x < count;) { set_display_off(); for (y = 0; y < ind; y++) { word = ((x + y) < count) ? next_arg(templist, &templist) : NULL; add_alias(VAR_ALIAS, var[y], word); } set_display(display); x += ind; parse_line(NULL, todo, subargs ? subargs : empty_string(), 0, 0, 0); } set_display_off(); for (y = 0; y < ind; y++) { delete_alias(VAR_ALIAS, var[y]); } set_display(display); new_free(&placeholder); }
/* * 'move_to_next_word': Move a "mark" from its current position to the * beginning of the "next" word. * * Arguments: * 'str' - a pointer to a character pointer -- The initial value is the * "mark", and it will be changed upon return to the beginning * of the previous word. * 'start' - The start of the string that (*str) points to. * 'extended' - Whether double quoted words shall be supported * 'delims' - The types of double quoets to honor (if applicable) * * Return value: * If (*str) is NULL or points to the end of a string (there is no next * word) the return value is 0. * Otherwise, the return value is 1. * * Notes: * Regardless of whether 'start' is actually the start of the string that * '*str' points to, this function will treat it as such and will never go * backwards further than 'start'. * If (*str) points to the nul that terminates 'start', then (*str) shall * be set to the first character in the last word in 'start'. * If (*str) points to the first character in any word, then (*str) shall * be set to the first character in the full word BEFORE (*str). * If (*str) points to the middle of a string, then (*str) shall be set to * the first character IN THAT WORD (*str) points to. * If (*str) points to a space, then (*str) shall be set to the first * character in the word before the space. * A "word" always begins on the second character after the end of a word * because the first character after a word is a space (which is reserved * because we might want to change it to a nul). That means if there is * more than one space between words, the first space belongs to the "left" * word and all the rest of the spaces belong to the "right" word! * EXCEPT WHEN there are trailing spaces on a string and we are already in the * last word (there is not a next word). In that case, ths current word * claims all of the trailing spaces and (*str) is set to the trailing nul. * * XXX - The debugging printfs are ugly. */ static int move_to_next_word (const char **str, const char *start, int extended, const char *delims) { char what; int simple; #if 0 const char * mark2; #endif const char * pos; /* * If there is not a word, then just stop right here. */ if (!str || !*str || !**str) return 0; if (x_debug & DEBUG_EXTRACTW_DEBUG) yell(">>>> move_to_next_word: mark [%s], start [%s], " "extended [%d], delims [%s]", *str, start, extended, delims); /* * If "delims" has only one character, then we can do the double * quote support simply (by comapring characters), otherwise we have * to do it by calling strchr() for each character. Ick. */ if (delims && delims[0] && delims[1] == 0) { if (x_debug & DEBUG_EXTRACTW_DEBUG) yell(".... move_to_next_word: Simple processing"); simple = 1; what = delims[0]; } else { if (x_debug & DEBUG_EXTRACTW_DEBUG) yell(".... move_to_next_word: Expensive processing"); simple = 0; what = 255; } /* * Here we check to see if we even want to do extended word support. * The user can always have the option to turn it off. */ CHECK_EXTENDED_SUPPORT if (x_debug & DEBUG_EXTRACTW_DEBUG) { yell(".... move_to_next_word: Extended word support requested [%d]", extended == DWORD_YES); yell(".... move_to_next_word: Extended word support for simple case valid [%d]", simple == 1 && **str == what); yell(".... move_to_next_word: Extended word support for complex case valid [%d]", simple == 0 && strchr(delims, **str)); } /* Start at where the user asked, eh? */ pos = *str; if (x_debug & DEBUG_EXTRACTW_DEBUG) yell(".... move_to_next_word: starting at [%s]", pos); /* * Always skip leading spaces */ while (*pos && isspace(*pos)) pos++; if (x_debug & DEBUG_EXTRACTW_DEBUG) yell(".... move_to_next_word: after skipping spaces, [%s]", pos); /* * Now check to see if this is an extended word. If it is an * extended word, move to the "end" of the word, which is the * matching puncutation mark. */ if (extended == DWORD_YES && ( (simple == 1 && *pos == what) || (simple == 0 && strchr(delims, *pos)) ) ) { const char * after; if (x_debug & DEBUG_EXTRACTW_DEBUG) yell(".... move_to_next_word: handling extended word"); if (!(after = find_forward_character(pos, start, delims))) panic("find_forward returned NULL [1]"); if (*after) after++; pos = after; if (x_debug & DEBUG_EXTRACTW_DEBUG) yell(".... move_to_next_word: after extended word [%s]", pos); } /* * If this is not an extended word, just skip to the next space. */ else { if (x_debug & DEBUG_EXTRACTW_DEBUG) yell(".... move_to_next_word: handling simple word [%s]", pos); while (*pos && !my_isspace(*pos)) pos++; if (x_debug & DEBUG_EXTRACTW_DEBUG) yell(".... move_to_next_word: at next space: [%s]", pos); } #if 0 /* * 'pos' now points at the space just after the end of the word; * This space belongs to us, but any further spaces do not long * belong to us, unless there are no more words after us! So we * need to check this. */ /* -- Is the rest of a string just spaces? -- */ if (x_debug & DEBUG_EXTRACTW_DEBUG) yell("... move_to_next_word: looking for another word..."); mark2 = pos; while (*mark2 && my_isspace(*mark2)) mark2++; if (!*mark2) /* Only spaces after this. Ok. */ { if (x_debug & DEBUG_EXTRACTW_DEBUG) yell("... move_to_next_word: didn't find one."); pos = mark2; } /* The start of the next word is after our space. */ else { if (x_debug & DEBUG_EXTRACTW_DEBUG) yell("... move_to_next_word: there's another word."); pos++; } #else if (*pos) pos++; #endif if (x_debug & DEBUG_EXTRACTW_DEBUG) yell("... move_to_next_word: next word starts with [%s]", pos); *str = pos; return 1; }
static VALUE epic_echo (VALUE module, VALUE string) { RUBY_STARTUP yell("%s", my_string); return Qnil; }
int main(int argc, char *argv[]) { struct apm_power_info apm_info; int apm_fd; int ch; int shutdown_mins = DEFAULT_SHUTDOWN_MINS; int warn_mins = DEFAULT_WARN_MINS; char *shutdown_cmd = DEFAULT_SHUTDOWN_CMD; char *warn_cmd_tmpl = DEFAULT_WARN_CMD; char warn_cmd[PATH_MAX]; char *p; while ((ch = getopt(argc, argv, "s:S:vw:W:")) != -1) { switch (ch) { case 's': shutdown_mins = strtol(optarg, &p, 10); if (*p || shutdown_mins < 1) errx(1, "illegal -s value: %s", optarg); /* NOTREACHED */ break; case 'S': shutdown_cmd = optarg; break; case 'v': verbose = 1; break; case 'w': warn_mins = strtol(optarg, &p, 10); if (*p || warn_mins < 1) errx(1, "illegal -w value: %s", optarg); /* NOTREACHED */ break; case 'W': warn_cmd_tmpl = optarg; break; default: usage(); /* NOTREACHED */ } } apm_fd = open("/dev/apm", O_RDONLY); if (apm_fd < 0) errx(1, "can't open /dev/apm"); if (!verbose) daemon(0, 0); for (;;) { if (ioctl(apm_fd, APM_IOC_GETPOWER, &apm_info) < 0) { yell("can't read apm power"); exit(1); } if (apm_info.ac_state == APM_AC_ON) goto sleeper; if (verbose) printf("low battery (%d%%), off ac, %d minute%s " "remaining\n", apm_info.battery_life, apm_info.minutes_left, (apm_info.minutes_left == 1 ? "" : "s")); if (apm_info.minutes_left <= warn_mins && !warned) { expand_warn_cmd(warn_cmd_tmpl, warn_cmd, PATH_MAX, shutdown_mins, &apm_info); yell("minutes remaining below %d, running warn " "command: %s", warn_mins, warn_cmd); warned = 1; execute(warn_cmd); } else if (apm_info.minutes_left <= shutdown_mins) { yell("minutes remaining below %d, running shutdown " "command: %s\n", shutdown_mins, shutdown_cmd); execute(shutdown_cmd); exit(0); } else if (apm_info.minutes_left >= warn_mins + 10) warned = 0; sleeper: sleep(5); } return (0); }
/* This function is used by CTCP handling, but not by xform! */ unsigned char * decipher_message (const unsigned char *ciphertext, size_t len, Crypt *key, int *retlen) { do { if (key->sed_type == CAST5CRYPT || key->sed_type == BLOWFISHCRYPT || key->sed_type == AES256CRYPT || key->sed_type == AESSHA256CRYPT || key->sed_type == FISHCRYPT) { unsigned char * outbuf = NULL; #ifdef HAVE_SSL const EVP_CIPHER *type; int bytes_to_trim; int ivsize, blocksize; if (key->sed_type == CAST5CRYPT) { ivsize = 8, blocksize = 8; } else if (key->sed_type == BLOWFISHCRYPT) { ivsize = 8, blocksize = 8; } else if (key->sed_type == FISHCRYPT) { ivsize = 0, blocksize = 8; } else if (key->sed_type == AES256CRYPT || key->sed_type == AESSHA256CRYPT) { ivsize = 16, blocksize = 16; } else return NULL; if (blocksize > 0 && len % blocksize != 0) { yell("Encrypted message [%s] isn't multiple of %d! (is %d)", ciphertext, blocksize, len); break; } if ((int)len < blocksize + ivsize) { yell("Encrypted message [%s] doesn't contain message! " "(len is %d)", ciphertext, len); break; } if (key->sed_type == CAST5CRYPT) type = EVP_cast5_cbc(); else if (key->sed_type == BLOWFISHCRYPT) type = EVP_bf_cbc(); else if (key->sed_type == FISHCRYPT) type = EVP_bf_ecb(); else if (key->sed_type == AES256CRYPT || key->sed_type == AESSHA256CRYPT) type = EVP_aes_256_cbc(); else break; /* Not supported */ if (!(outbuf = decipher_evp(key->key, key->keylen, ciphertext, len, type, retlen, ivsize))) { yell("bummer"); break; } bytes_to_trim = outbuf[len - 1] & (blocksize - 1); /* outbuf[len - bytes_to_trim - 1] = 0; */ outbuf[len - bytes_to_trim] = 0; memmove(outbuf, outbuf + ivsize, len - ivsize); #endif return outbuf; } else if (key->sed_type == SEDCRYPT || key->sed_type == SEDSHACRYPT) { unsigned char * text; text = new_malloc(len + 1); memmove(text, ciphertext, len); decrypt_sed(text, len, key->key, key->keylen); *retlen = len; return text; } else if (key->sed_type == PROGCRYPT) { unsigned char *retval; retval = decrypt_by_prog(ciphertext, &len, key); *retlen = len; return retval; } else panic(1, "decipher_message: key->sed_type %d is not valid", key->sed_type); } while (0); return NULL; }
unsigned char * cipher_message (const unsigned char *orig_message, size_t len, Crypt *key, int *retlen) { if (retlen) *retlen = 0; if (!orig_message || !key || !retlen) return NULL; if (key->sed_type == CAST5CRYPT || key->sed_type == BLOWFISHCRYPT || key->sed_type == FISHCRYPT || key->sed_type == AES256CRYPT || key->sed_type == AESSHA256CRYPT) { unsigned char *ciphertext = NULL; #ifdef HAVE_SSL size_t ivlen; const EVP_CIPHER *type; if (key->sed_type == CAST5CRYPT) { type = EVP_cast5_cbc(); ivlen = 8; } else if (key->sed_type == BLOWFISHCRYPT) { type = EVP_bf_cbc(); ivlen = 8; } else if (key->sed_type == FISHCRYPT) { type = EVP_bf_ecb(); ivlen = 0; /* XXX Sigh */ } else if (key->sed_type == AES256CRYPT || key->sed_type == AESSHA256CRYPT) { type = EVP_aes_256_cbc(); ivlen = 16; } else return NULL; /* Not supported */ if (!(ciphertext = cipher_evp(key->key, key->keylen, orig_message, len, type, retlen, ivlen))) { yell("bummer"); return NULL; } #endif return ciphertext; } else if (key->sed_type == SEDCRYPT || key->sed_type == SEDSHACRYPT) { unsigned char * ciphertext; ciphertext = new_malloc(len + 1); memmove(ciphertext, orig_message, len); encrypt_sed(ciphertext, len, key->key, strlen(key->key)); *retlen = len; return ciphertext; } else if (key->sed_type == PROGCRYPT) { unsigned char *ciphertext; ciphertext = encrypt_by_prog(orig_message, &len, key); *retlen = len; return ciphertext; } else panic(1, "cipher_message: key->sed_type %d is not valid", key->sed_type); return NULL; }
/* * numbered_command: does (hopefully) the right thing with the numbered * responses from the server. I wasn't real careful to be sure I got them * all, but the default case should handle any I missed (sorry) */ void numbered_command(u_char *from, int comm, u_char **ArgList) { u_char *user; u_char none_of_these = 0; u_char blah[BIG_BUFFER_SIZE]; int flag, lastlog_level; const int from_server = parsing_server(); #if 0 int user_cnt, inv_cnt, server_cnt; #endif /* 0 */ if (!from || !*from) return; if (!*ArgList[0]) user = NULL; else user = ArgList[0]; if (!ArgList[1]) return; lastlog_level = set_lastlog_msg_level(LOG_CRAP); save_message_from(); message_from(NULL, LOG_CRAP); ArgList++; current_numeric_local = -comm; /* must be negative of numeric! */ switch (comm) { case 001: /* #define RPL_WELCOME 001 */ PasteArgs(ArgList, 0); if (my_strcmp(user, server_get_nickname(from_server)) != 0) { yell("=== Setting this servers nickname to \"%s\" from \"%s\"", user, server_get_nickname(from_server)); server_set_nickname(from_server, user); } if (do_hook(current_numeric(), "%s %s", from, *ArgList)) display_msg(from, ArgList); clean_whois_queue(); break; case 002: /* #define RPL_YOURHOST 002 */ PasteArgs(ArgList, 0); snprintf(CP(blah), sizeof blah, "*** %s", ArgList[0]); got_initial_version(blah); if (do_hook(current_numeric(), "%s %s", from, *ArgList)) display_msg(from, ArgList); break; /* should do something with this some day, 2.8 had channel/user mode switches */ case 004: /* #define RPL_MYINFO 004 */ PasteArgs(ArgList, 0); if (do_hook(current_numeric(), "%s %s", from, *ArgList)) display_msg(from, ArgList); break; /* * this part of ircii has been broken for most of ircd 2.7, so someday I'll * make it work for ircd 2.8 ... phone.. */ #if 0 case 251: /* #define RPL_LUSERCLIENT 251 */ display_msg(from, ArgList); if (is_server_connected(from_server)) break; if (from_server == get_primary_server() && ((sscanf(ArgList[1], "There are %d users and %d invisible on %d servers", &user_cnt, &inv_cnt, &server_cnt) == 3)||(sscanf(ArgList[1], "There are %d users and %d invisible on %d servers", &user_cnt, &inv_cnt, &server_cnt) == 3))) { user_cnt =+ inv_cnt; if ((server_cnt < get_int_var(MINIMUM_SERVERS_VAR)) || (user_cnt < get_int_var(MINIMUM_USERS_VAR))) { say("Trying better populated server..."); get_connected(from_server + 1); } } break; #endif /* 0 */ case 301: /* #define RPL_AWAY 301 */ user_is_away(from, ArgList); break; case 302: /* #define RPL_USERHOST 302 */ userhost_returned(from, ArgList); break; case 303: /* #define RPL_ISON 303 */ ison_returned(from, ArgList); break; case 311: /* #define RPL_WHOISUSER 311 */ whois_name(from, ArgList); break; case 312: /* #define RPL_WHOISSERVER 312 */ whois_server(from, ArgList); break; case 313: /* #define RPL_WHOISOPERATOR 313 */ whois_oper(from, ArgList); break; case 314: /* #define RPL_WHOWASUSER 314 */ whowas_name(from, ArgList); break; case 316: /* #define RPL_WHOISCHANOP 316 */ whois_chop(from, ArgList); break; case 317: /* #define RPL_WHOISIDLE 317 */ whois_lastcom(from, ArgList); break; case 318: /* #define RPL_ENDOFWHOIS 318 */ end_of_whois(from, ArgList); break; case 319: /* #define RPL_WHOISCHANNELS 319 */ whois_channels(from, ArgList); break; case 321: /* #define RPL_LISTSTART 321 */ ArgList[0] = UP("Channel\0Users\0Topic"); ArgList[1] = ArgList[0] + 8; ArgList[2] = ArgList[1] + 6; ArgList[3] = NULL; funny_list(from, ArgList); break; case 322: /* #define RPL_LIST 322 */ funny_list(from, ArgList); break; case 324: /* #define RPL_CHANNELMODEIS 324 */ funny_mode(from, ArgList); break; case 341: /* #define RPL_INVITING 341 */ invite(from, ArgList); break; case 352: /* #define RPL_WHOREPLY 352 */ whoreply(NULL, ArgList); break; case 353: /* #define RPL_NAMREPLY 353 */ funny_namreply(from, ArgList); break; case 366: /* #define RPL_ENDOFNAMES 366 */ { u_char *tmp = NULL, *chan; PasteArgs(ArgList, 0); malloc_strcpy(&tmp, ArgList[0]); chan = next_arg(tmp, 0); flag = do_hook(current_numeric(), "%s %s", from, ArgList[0]); if (flag && channel_mode_lookup(chan, CHAN_NAMES | CHAN_MODE, 0) && get_int_var(SHOW_END_OF_MSGS_VAR) && flag) display_msg(from, ArgList); new_free(&tmp); } break; case 381: /* #define RPL_YOUREOPER 381 */ PasteArgs(ArgList, 0); if (do_hook(current_numeric(), "%s %s", from, *ArgList)) display_msg(from, ArgList); server_set_operator(parsing_server(), 1); update_all_status(); /* fix the status line */ break; case 401: /* #define ERR_NOSUCHNICK 401 */ no_such_nickname(from, ArgList); break; case 405: /* #define ERR_TOOMANYCHANNELS 405 */ remove_channel(ArgList[0], parsing_server()); break; case 421: /* #define ERR_UNKNOWNCOMMAND 421 */ if (check_screen_redirect(ArgList[0])) break; if (check_wait_command(ArgList[0])) break; PasteArgs(ArgList, 0); flag = do_hook(current_numeric(), "%s %s", from, *ArgList); if (!my_strncmp("ISON", *ArgList, 4) || !my_strncmp("USERHOST", *ArgList, 8)) { server_set_2_6_2(parsing_server(), 0); convert_to_whois(); } else if (flag) display_msg(from, ArgList); break; case 432: /* #define ERR_ERRONEUSNICKNAME 432 */ case 433: /* #define ERR_NICKNAMEINUSE 433 */ PasteArgs(ArgList, 0); if (do_hook(current_numeric(), "%s %s", from, *ArgList)) display_msg(from, ArgList); reset_nickname(from); break; case 437: /* #define ERR_UNAVAILRESOURCE 437 */ PasteArgs(ArgList, 0); if (do_hook(current_numeric(), "%s %s", from, *ArgList)) display_msg(from, ArgList); if (!is_channel(*ArgList)) reset_nickname(from); break; case 463: /* #define ERR_NOPERMFORHOST 463 */ display_msg(from, ArgList); close_server(parsing_server(), empty_string()); window_check_servers(); if (!connected_to_server()) get_connected(parsing_server() + 1); break; case 464: /* #define ERR_PASSWDMISMATCH 464 */ PasteArgs(ArgList, 0); flag = do_hook(current_numeric(), "%s %s", from, ArgList[0]); if (server_get_oper_command()) { if (flag) display_msg(from, ArgList); } else get_password(); break; case 465: /* #define ERR_YOUREBANNEDCREEP 465 */ { int klined_server = parsing_server(); PasteArgs(ArgList, 0); if (do_hook(current_numeric(), "%s %s", from, ArgList[0])) display_msg(from, ArgList); close_server(parsing_server(), empty_string()); window_check_servers(); if (number_of_servers() > 1) remove_from_server_list(klined_server); if (!connected_to_server()) say("You are not connected to a server. Use /SERVER to connect."); break; } case 471: /* #define ERR_CHANNELISFULL 471 */ case 473: /* #define ERR_INVITEONLYCHAN 473 */ case 474: /* #define ERR_BANNEDFROMCHAN 474 */ case 475: /* #define ERR_BADCHANNELKEY 475 */ case 476: /* #define ERR_BADCHANMASK 476 */ cannot_join_channel(from, ArgList); break; case 484: /* #define ERR_RESTRICTED 484 */ if (do_hook(current_numeric(), "%s %s", from, *ArgList)) display_msg(from, ArgList); server_set_flag(parsing_server(), USER_MODE_R, 1); break; /* * The following accumulates the remaining arguments * in ArgSpace for hook detection. We can't use * PasteArgs here because we still need the arguments * separated for use elsewhere. */ default: { u_char *ArgSpace = NULL; int i, do_message_from = 0; size_t len; for (i = len = 0; ArgList[i]; len += my_strlen(ArgList[i++])) ; len += (i - 1); ArgSpace = new_malloc(len + 1); ArgSpace[0] = '\0'; /* this is cheating */ if (ArgList[0] && is_channel(ArgList[0])) do_message_from = 1; for (i = 0; ArgList[i]; i++) { if (i) my_strcat(ArgSpace, " "); my_strcat(ArgSpace, ArgList[i]); } if (do_message_from) message_from(ArgList[0], LOG_CRAP); i = do_hook(current_numeric(), "%s %s", from, ArgSpace); new_free(&ArgSpace); if (do_message_from) restore_message_from(); if (i == 0) goto done; none_of_these = 1; } } /* the following do not hurt the ircII if intercepted by a hook */ if (none_of_these) { switch (comm) { case 221: /* #define RPL_UMODEIS 221 */ put_it("%s Your user mode is \"%s\"", numeric_banner(), ArgList[0]); break; case 242: /* #define RPL_STATSUPTIME 242 */ PasteArgs(ArgList, 0); if (from && !my_strnicmp(server_get_itsname(parsing_server()), from, my_strlen(server_get_itsname(parsing_server())))) from = NULL; if (from) put_it("%s %s from (%s)", numeric_banner(), *ArgList, from); else put_it("%s %s", numeric_banner(), *ArgList); break; case 332: /* #define RPL_TOPIC 332 */ channel_topic(from, ArgList); break; case 351: /* #define RPL_VERSION 351 */ version(from, ArgList); break; case 364: /* #define RPL_LINKS 364 */ if (ArgList[2]) { PasteArgs(ArgList, 2); put_it("%s %-20s %-20s %s", numeric_banner(), ArgList[0], ArgList[1], ArgList[2]); } else { PasteArgs(ArgList, 1); put_it("%s %-20s %s", numeric_banner(), ArgList[0], ArgList[1]); } break; case 372: /* #define RPL_MOTD 372 */ if (!get_int_var(SUPPRESS_SERVER_MOTD_VAR) || !server_get_motd(parsing_server())) { PasteArgs(ArgList, 0); put_it("%s %s", numeric_banner(), ArgList[0]); } break; case 375: /* #define RPL_MOTDSTART 375 */ if (!get_int_var(SUPPRESS_SERVER_MOTD_VAR) || !server_get_motd(parsing_server())) { PasteArgs(ArgList, 0); put_it("%s %s", numeric_banner(), ArgList[0]); } break; case 376: /* #define RPL_ENDOFMOTD 376 */ if (server_get_attempting_to_connect(parsing_server())) got_initial_version(UP("*** Your host is broken and not running any version")); if (get_int_var(SHOW_END_OF_MSGS_VAR) && (!get_int_var(SUPPRESS_SERVER_MOTD_VAR) || !server_get_motd(parsing_server()))) { PasteArgs(ArgList, 0); put_it("%s %s", numeric_banner(), ArgList[0]); } server_set_motd(parsing_server(), 0); break; case 384: /* #define RPL_MYPORTIS 384 */ PasteArgs(ArgList, 0); put_it("%s %s %s", numeric_banner(), ArgList[0], user); break; case 385: /* #define RPL_NOTOPERANYMORE 385 */ server_set_operator(parsing_server(), 0); display_msg(from, ArgList); update_all_status(); break; case 403: /* #define ERR_NOSUCHCHANNEL 403 */ not_valid_channel(from, ArgList); break; case 451: /* #define ERR_NOTREGISTERED 451 */ /* * Sometimes the server doesn't catch the USER line, so * here we send a simplified version again -lynx */ send_to_server("USER %s %s . :%s", my_username(), irc_umode(), my_realname()); send_to_server("NICK %s", server_get_nickname(parsing_server())); break; case 462: /* #define ERR_ALREADYREGISTRED 462 */ display_msg(from, ArgList); break; #define RPL_CLOSEEND 363 #define RPL_SERVLISTEND 235 case 315: /* #define RPL_ENDOFWHO 315 */ case 323: /* #define RPL_LISTEND 323 */ funny_print_widelist(); case 219: /* #define RPL_ENDOFSTATS 219 */ case 232: /* #define RPL_ENDOFSERVICES 232 */ case 365: /* #define RPL_ENDOFLINKS 365 */ case 368: /* #define RPL_ENDOFBANLIST 368 */ case 369: /* #define RPL_ENDOFWHOWAS 369 */ case 374: /* #define RPL_ENDOFINFO 374 */ #if 0 /* this case needs special handing - see above */ case 376: /* #define RPL_ENDOFMOTD 376 */ #endif /* 0 */ case 394: /* #define RPL_ENDOFUSERS 394 */ if (!get_int_var(SHOW_END_OF_MSGS_VAR)) break; default: display_msg(from, ArgList); } } set_lastlog_msg_level(lastlog_level); done: restore_message_from(); }
/* * numbered_command: does (hopefully) the right thing with the numbered * responses from the server. I wasn't real careful to be sure I got them * all, but the default case should handle any I missed (sorry) * * The format of a numeric looks like so: * * :server-name XXX our-nick Arg1 Arg2 Arg3 ... :ArgN * * The last argument traditionally has a colon before it, but this is not * compulsary. The BreakArgs function has already broken this up into * words for us, so that what we get, looks like this: * * server-name -> from parameter * XXX -> comm parameter * our-nick -> ArgList[0] * Arg1 -> ArgList[1] * Arg2 -> ArgList[2] * ... ... * * BUT! There's a wrinkle in the ointment. The first thing we do is slurp * up ArgList[0] (our-nick) and put it in 'user'. Then we increment the * ArgList array, so what we actually end up with is: * * server-name -> from parameter * XXX -> comm parameter * our-nick -> user * Arg1 -> ArgList[0] * Arg2 -> ArgList[1] * ... ... * ArgN -> ArgList[N-1] * NULL -> ArgList[N] */ void numbered_command (const char *from, const char *comm, char const **ArgList) { const char *target; char *copy; int i; int lastlog_level; int old_current_numeric = current_numeric; int numeric; /* All numerics must have a target (our nickname) */ if (!comm || !*comm) { rfc1459_odd(from, comm, ArgList); return; } numeric = atol(comm); if (numeric < 0 || numeric > 999) { rfc1459_odd(from, comm, ArgList); return; } if (!(target = ArgList[0])) { rfc1459_odd(from, comm, ArgList); return; } ArgList++; lastlog_level = set_lastlog_msg_level(LOG_CRAP); if (ArgList[0] && is_channel(ArgList[0])) message_from(ArgList[0], LOG_CRAP); else message_from(NULL, LOG_CRAP); current_numeric = -numeric; /* must be negative of numeric! */ /* * This first switch statement is only used for those numerics * which either need to perform some action before the numeric * is offered to the user, or by those actions which need to offer * the numeric to the user in some special manner. * * Those numerics which require only special display if the user * does not hook them, are handled below. * * Those numerics which require special action after the numeric * is offered to the user, are also handled below. * * Each of these numerics must either "break" (go to step 2) * or must "goto END" (goto step 3). */ switch (numeric) { /* * I added the "set_server_nickname" here because the client * when auto-fudging your nick will sometimes be confused as * what your nickname really is when you connect. Since the * server always tells us who the message was set to (ie, us) * we just kind of take it at its word. */ case 001: /* #define RPL_WELCOME 001 */ { Timeval i; i.tv_sec = 0; i.tv_usec = 50000; select(0, NULL, NULL, NULL, &i); accept_server_nickname(from_server, target); server_is_registered(from_server, 1); userhostbase(from_server, NULL, got_my_userhost, 1); break; } /* * Now instead of the terribly horrible hack using numeric 002 * to get the server name/server version info, we use the 004 * numeric which is what is the most logical choice for it. * * If any of the arguments are missing, we don't abort, because * the client needs 004 to sync. Instead, we just pass in the * NULL values and hope for the best... */ case 004: /* #define RPL_MYINFO 004 */ { const char *server = NULL, *version = NULL, *umodes = NULL; /* The 004 numeric is too import to "odd server stuff" over. */ /* So if the reply is useless, we'll just wing it */ if (!(server = ArgList[0])) server = version = umodes = NULL; else if (!(version = ArgList[1])) server = version = umodes = NULL; else if (!(umodes = ArgList[2])) server = version = umodes = NULL; else { /* Work around ratbox-1.2-3. */ if (!my_stricmp(umodes, "(brown")) if (ArgList[3] && !my_stricmp(ArgList[3], "paper")) if (ArgList[4] && !my_stricmp(ArgList[4], "bag")) if (ArgList[5] && !my_stricmp(ArgList[5], "release)")) { if (!(umodes = ArgList[6])) { rfc1459_odd(from, comm, ArgList); goto END; } } } got_initial_version_28(server, version, umodes); break; } case 005: { int arg; char *set, *value; for (arg = 0; ArgList[arg] && !strchr(ArgList[arg], ' '); arg++) { set = LOCAL_COPY(ArgList[arg]); value = strchr(set, '='); if (value && *value) *value++ = 0; if (*set == '+') /* parameter append */ { const char *ov = get_server_005(from_server, ++set); value = malloc_strdup2(ov, value); set_server_005(from_server, set, value); new_free(&value); } else if (*set == '-') /* parameter removal */ set_server_005(from_server, ++set, NULL); else if (value && *value) set_server_005(from_server, set, value); else set_server_005(from_server, set, space); } break; } case 10: /* EFNext "Use another server" 010 */ { const char *new_server, *new_port_s, *message; int new_port, old_server; PasteArgs(ArgList, 2); if (!(new_server = ArgList[0])) { rfc1459_odd(from, comm, ArgList); goto END; } if (!(new_port_s = ArgList[1])) { rfc1459_odd(from, comm, ArgList); goto END; } if (!(message = ArgList[2])) { rfc1459_odd(from, comm, ArgList); goto END; } new_port = atol(ArgList[1]); /* Must do these things before calling "display_msg" */ old_server = from_server; add_to_server_list(new_server, new_port, NULL, NULL, get_server_group(from_server), NULL, 0); server_reconnects_to(old_server, from_server); from_server = old_server; break; } case 14: /* Erf/TS4 "cookie" numeric 014 */ { const char * cookie; PasteArgs(ArgList, 0); if (!(cookie = ArgList[0])) { rfc1459_odd(from, comm, ArgList); goto END; } use_server_cookie(from_server); set_server_cookie(from_server, cookie); goto END; } case 42: /* ircnet's "unique id" numeric 042 */ { const char * unique_id; const char * message; PasteArgs(ArgList, 1); if (!(unique_id = ArgList[0])) { rfc1459_odd(from, comm, ArgList); goto END; } else if (!(message = ArgList[1])) { rfc1459_odd(from, comm, ArgList); goto END; } set_server_unique_id(from_server, unique_id); if (do_hook(current_numeric, "%s %s %s", from, unique_id, message)) goto DISPLAY; goto END; } case 301: /* #define RPL_AWAY 301 */ { const char *nick, *message; PasteArgs(ArgList, 1); if (!(nick = ArgList[0])) { rfc1459_odd(from, comm, ArgList); goto END; } if (!(message = ArgList[1])) { rfc1459_odd(from, comm, ArgList); goto END; } /* Ach. /on 301 doesn't offer 'from' as $0. Bummer. */ if (do_hook(current_numeric, "%s %s", nick, message)) goto DISPLAY; goto END; } case 340: /* #define RPL_USERIP 307 */ if (!get_server_005(from_server, "USERIP")) break; /* FALLTHROUGH */ case 302: /* #define RPL_USERHOST 302 */ userhost_returned(from_server, from, comm, ArgList); goto END; case 303: /* #define RPL_ISON 303 */ ison_returned(from_server, from, comm, ArgList); goto END; case 315: /* #define RPL_ENDOFWHO 315 */ who_end(from_server, from, comm, ArgList); goto END; case 321: /* #define RPL_LISTSTART 321 */ { const char *channel, *user_cnt, *line; channel = ArgList[0] = "Channel"; user_cnt = ArgList[1] = "Users"; line = ArgList[2] = "Topic"; ArgList[3] = NULL; /* Then see if they want to hook /ON LIST */ if (!do_hook(LIST_LIST, "%s %s %s", channel, user_cnt, line)) goto END; /* * Otherwise, this line is ok. */ break; } case 322: /* #define RPL_LIST 322 */ { const char *channel, *user_cnt, *line; int cnt; int funny_flags, funny_min, funny_max; const char *funny_match; PasteArgs(ArgList, 2); if (!(channel = ArgList[0])) { rfc1459_odd(from, comm, ArgList); goto END; } if (!(user_cnt = ArgList[1])) { rfc1459_odd(from, comm, ArgList); goto END; } if (!(line = ArgList[2])) { rfc1459_odd(from, comm, ArgList); goto END; } funny_flags = get_server_funny_flags(from_server); funny_min = get_server_funny_min(from_server); funny_max = get_server_funny_max(from_server); funny_match = get_server_funny_match(from_server); /* * Do not display if the channel has no topic and the user asked * for only channels with topics. */ if (funny_flags & FUNNY_TOPIC && !(line && *line)) goto END; /* * Do not display if the channel does not have the necessary * number of users the user asked for */ cnt = my_atol(user_cnt); if (funny_min && (cnt < funny_min)) goto END; if (funny_max && (cnt > funny_max)) goto END; /* * Do not display if the channel is not private or public as the * user requested. */ if ((funny_flags & FUNNY_PRIVATE) && (*channel != '*')) goto END; if ((funny_flags & FUNNY_PUBLIC) && (*channel == '*')) goto END; /* * Do not display if the channel does not match the user's * supplied wildcard pattern */ if (funny_match && wild_match(funny_match, channel) == 0) goto END; /* Then see if they want to hook /ON LIST */ if (!do_hook(LIST_LIST, "%s %s %s", channel, user_cnt, line)) goto END; /* * Otherwise, this line is ok. */ break; } case 324: /* #define RPL_CHANNELMODEIS 324 */ { const char *mode, *channel; PasteArgs(ArgList, 1); if (!(channel = ArgList[0])) { rfc1459_odd(from, comm, ArgList); goto END; } if (!(mode = ArgList[1])) { rfc1459_odd(from, comm, ArgList); goto END; } /* If we're waiting for MODE reply. */ if (channel_is_syncing(channel, from_server)) { int numonchannel, maxnum; copy = LOCAL_COPY(channel); update_channel_mode(channel, mode); update_all_status(); maxnum = get_server_max_cached_chan_size(from_server); if (maxnum >= 0) { numonchannel = number_on_channel(copy, from_server); if (numonchannel <= maxnum) whobase(from_server, copy, add_user_who, add_user_end); else channel_not_waiting(copy, from_server); } else whobase(from_server, copy, add_user_who, add_user_end); #if 0 goto END; #endif } break; } case 352: /* #define RPL_WHOREPLY 352 */ whoreply(from_server, NULL, comm, ArgList); goto END; case 353: /* #define RPL_NAMREPLY 353 */ { const char *type, *channel, *line; PasteArgs(ArgList, 2); if (!(type = ArgList[0])) { rfc1459_odd(from, comm, ArgList); goto END; } if (!(channel = ArgList[1])) { rfc1459_odd(from, comm, ArgList); goto END; } if (!(line = ArgList[2])) { line = empty_string; } if (channel_is_syncing(channel, from_server)) { char *line_copy = LOCAL_COPY(line); char *nick; while ((nick = next_arg(line_copy, &line_copy)) != NULL) { /* XXX - Hack to work around space at end of 353 */ forcibly_remove_trailing_spaces(nick, NULL); /* * 1999 Oct 29 -- This is a hack to compensate for * a bug in older ircd implementations that can result * in a truncated nickname at the end of a names reply. * The last nickname in a names list is then always * treated with suspicion until the WHO reply is * completed and we know that its not truncated. --esl */ if (!line || !*line) add_to_channel(channel, nick, from_server, 1, 0, 0, 0); else add_to_channel(channel, nick, from_server, 0, 0, 0, 0); } message_from(channel, LOG_CRAP); break; } else { int cnt; const char *ptr; int funny_flags, funny_min, funny_max; const char *funny_match; funny_flags = get_server_funny_flags(from_server); funny_min = get_server_funny_min(from_server); funny_max = get_server_funny_max(from_server); funny_match = get_server_funny_match(from_server); ptr = line; for (cnt = -1; ptr; cnt++) { if ((ptr = strchr(ptr, ' ')) != NULL) ptr++; } if (funny_min && (cnt < funny_min)) goto END; else if (funny_max && (cnt > funny_max)) goto END; if ((funny_flags & FUNNY_PRIVATE) && (*type == '=')) goto END; if ((funny_flags & FUNNY_PUBLIC) && ((*type == '*') || (*type == '@'))) goto END; if (funny_match && wild_match(funny_match, channel) == 0) goto END; } /* Everything is OK. */ break; } case 354: /* #define RPL_XWHOREPLY 354 */ xwhoreply(from_server, NULL, comm, ArgList); goto END; /* XXX Yea yea, these are out of order. so shoot me. */ case 346: /* #define RPL_INVITELIST (+I for erf) */ case 348: /* #define RPL_EXCEPTLIST (+e for erf) */ case 367: /* #define RPL_BANLIST */ number_of_bans++; break; case 347: /* #define END_OF_INVITELIST */ case 349: /* #define END_OF_EXCEPTLIST */ case 368: /* #define END_OF_BANLIST */ { const char *channel; if (!get_int_var(SHOW_END_OF_MSGS_VAR)) goto END; if (!(channel = ArgList[0])) { rfc1459_odd(from, comm, ArgList); goto END; } #ifdef IRCII_LIKE_BAN_SUMMARY if (do_hook(current_numeric, "%s %s %d", from, channel, number_of_bans)) #else if (do_hook(current_numeric, "%s %d %s", from, number_of_bans, channel)) #endif { put_it("%s Total number of %s on %s - %d", banner(), numeric == 347 ? "invites" : (numeric == 349 ? "exceptions" : (numeric == 368 ? "bans" : "wounds")), channel, number_of_bans); } goto END; } /* XXX Shouldn't this set "You're operator" flag for hybrid? */ case 381: /* #define RPL_YOUREOPER 381 */ if (!is_server_registered(from_server)) { rfc1459_odd(from, comm, ArgList); goto END; } break; /* ":%s 401 %s %s :No such nick/channel" */ case 401: /* #define ERR_NOSUCHNICK 401 */ { const char *nick; if (!(nick = ArgList[0])) { rfc1459_odd(from, comm, ArgList); goto END; } if (!is_channel(nick)) { notify_mark(from_server, nick, 0, 0); if (get_int_var(AUTO_WHOWAS_VAR)) { int foo = get_int_var(NUM_OF_WHOWAS_VAR); if (foo > -1) send_to_server("WHOWAS %s %d", nick, foo); else send_to_server("WHOWAS %s", nick); } } break; } /* Bizarre dalnet extended who replies. */ /* ":%s 402 %s %s :No such server" */ case 402: { const char *server; if (!(server = ArgList[0])) { rfc1459_odd(from, comm, ArgList); goto END; } fake_who_end(from_server, from, comm, server); break; } /* Yet more bizarre dalnet extended who replies. */ /* ":%s 522 %s :/WHO Syntax incorrect, use /who ? for help" */ /* ":%s 523 %s :Error, /who limit of %d exceed." */ case 522: case 523: { /* * This dalnet error message doesn't even give us the * courtesy of telling us which who request was in error, * so we have to guess. Whee. */ fake_who_end(from_server, from, comm, NULL); break; } case 403: /* #define ERR_NOSUCHCHANNEL 403 */ { const char * s; const char * channel; const char * message; PasteArgs(ArgList, 1); /* Some servers BBC and send back an empty reply. */ if (!(channel = ArgList[0])) { rfc1459_odd(from, comm, ArgList); goto END; } if (!(message = ArgList[1])) { rfc1459_odd(from, comm, ArgList); goto END; } /* Do not accept 403's from remote servers. */ s = get_server_itsname(from_server); if (my_strnicmp(s, from, strlen(s))) { rfc1459_odd(from, comm, ArgList); goto END; } /* * Some servers BBC and send this instead of a * 315 numeric when a who request has been completed. */ if (fake_who_end(from_server, from, comm, channel)) ; /* * If you try to JOIN or PART the "*" named channel, as may * happen if epic gets confused, the server may tell us that * channel does not exist. But it would be death to try to * destroy that channel as epic will surely do the wrong thing! * Otherwise, we somehow tried to reference a channel that * this server claims does not exist; we blow the channel away * for good measure. */ else if (strcmp(channel, "*")) remove_channel(channel, from_server); break; } case 421: /* #define ERR_UNKNOWNCOMMAND 421 */ { const char *token; if (!(token = ArgList[0])) { rfc1459_odd(from, comm, ArgList); goto END; } if (check_server_redirect(from_server, token)) goto END; if (check_server_wait(from_server, token)) goto END; break; } case 432: /* #define ERR_ERRONEUSNICKNAME 432 */ { const char *nick; if (!(nick = ArgList[0])) { rfc1459_odd(from, comm, ArgList); goto END; } if (!my_stricmp(target, nick)) yell("WARNING: Strange invalid nick message received." " You are probably lagged."); else if (get_int_var(AUTO_NEW_NICK_VAR)) fudge_nickname(from_server); else reset_nickname(from_server); break; } case 437: /* av2.9's "Nick collision" numeric 437 */ /* Also, undernet/dalnet "You are banned" */ /* Also, av2.10's "Can't do that" numeric */ /* Also, cs's "too many nick changes" num */ { /* * Ugh. What a total trainwreck this is. Sometimes, I * really hate all the ircd's out there in the world that * have to be supported. * * Well, there are at least four different, occasionally * scrutable ways we can get this numeric. * * 1a) On ircnet -- As an unregistered user, the NICK that * we are trying to register was used in the past 90 * seconds or so. The server expects us to send * another NICK request. * ARGV[0] IS NICK, REGISTERED IS NO * 1b) On ircnet -- As a registered user, the NICK that * we are trying to register was used in the past 90 * seconds or so. The server expects us not to do * anything (like a 432 numeric). * ARGV[0] IS NICK, REGISTERED IS YES * 2) On ircnet -- As a registered user, we are trying to * join a channel that was netsplit in the past 24 hours * or so. The server expects us not to do anything. * ARGV[0] IS CHANNEL, REGISTERED IS YES * 3) On undernet/dalnet -- As a registered user, who is * on a channel where we are banned, a NICK request * was rejected (because we are banned). The server * expects us not to do anything. * ARGV[0] IS CHANNEL, REGISTERED IS YES * 4) On a comstud efnet servers -- As a registered user, * we have changed our nicknames too many times in * too short a time. The server expects us not to do * anything. * ARGV[0] IS ERROR, ARGV[1] IS NULL. * I understand this numeric will be moving to 439. */ /* * Weed out the comstud one first, since it's the most bizarre. */ if (ArgList[0] && ArgList[1] == NULL) { accept_server_nickname(from_server, target); break; } /* * Now if it's a channel, it might be ircnet telling us we * can't join the channel, or undernet telling us that we * can't change our nickname because we're banned. The * easiest way to tell is to see if we are on the channel. */ if (is_channel(ArgList[0])) { /* XXX Is this really neccesary? */ if (!im_on_channel(ArgList[0], from_server)) remove_channel(ArgList[0], from_server); break; } /* * Otherwise, a nick command failed. Oh boy. * If we are registered, abort the nick change and * hope for the best. */ if (is_server_registered(from_server)) { accept_server_nickname(from_server, target); break; } /* * Otherwise, it's an ircnet "nick not available" error. * Let the nickname reset numerics handle this mess. */ /* FALLTHROUGH */ } case 433: /* #define ERR_NICKNAMEINUSE 433 */ case 438: /* EFnet/TS4 "nick collision" numeric 438 */ case 453: /* EFnet/TS4 "nickname lost" numeric 453 */ { const char *nick; if (!(nick = ArgList[0])) { rfc1459_odd(from, comm, ArgList); goto END; } if (!my_stricmp(target, nick)) /* * This should stop the "rolling nicks" in their tracks. */ yell("WARNING: Strange invalid nick message received." " You are probably lagged."); else if (get_int_var(AUTO_NEW_NICK_VAR)) fudge_nickname(from_server); else reset_nickname(from_server); if (!from) from = "-1"; break; } case 439: /* Comstud's "Can't change nickname" */ { accept_server_nickname(from_server, target); break; } case 442: /* #define ERR_NOTONCHANNEL 442 */ { const char * s; const char * channel; const char * message; PasteArgs(ArgList, 1); /* Some servers BBC and send back an empty reply. */ if (!(channel = ArgList[0])) { rfc1459_odd(from, comm, ArgList); goto END; } if (!(message = ArgList[1])) { rfc1459_odd(from, comm, ArgList); goto END; } /* Do not accept this numeric from remote servers */ s = get_server_itsname(from_server); if (my_strnicmp(s, from, strlen(s))) { rfc1459_odd(from, comm, ArgList); goto END; } /* Do not ever delete the "*" channel */ if (strcmp(ArgList[0], "*")) remove_channel(ArgList[0], from_server); break; } case 451: /* #define ERR_NOTREGISTERED 451 */ /* * Sometimes the server doesn't catch the USER line, so * here we send a simplified version again -lynx */ register_server(from_server, NULL); break; case 462: /* #define ERR_ALREADYREGISTRED 462 */ change_server_nickname(from_server, NULL); break; case 465: /* #define ERR_YOUREBANNEDCREEP 465 */ { /* * There used to be a say() here, but if we arent * connected to a server, then doing say() is not * a good idea. So now it just doesnt do anything. */ server_reconnects_to(from_server, NOSERV); break; } case 477: /* #define ERR_NEEDREGGEDNICK 477 */ /* IRCnet has a different 477 numeric. */ if (ArgList[0] && *ArgList[0] == '+') break; /* FALLTHROUGH */ case 471: /* #define ERR_CHANNELISFULL 471 */ case 473: /* #define ERR_INVITEONLYCHAN 473 */ case 474: /* #define ERR_BANNEDFROMCHAN 474 */ case 475: /* #define ERR_BADCHANNELKEY 475 */ case 476: /* #define ERR_BADCHANMASK 476 */ { const char *channel; if (!(channel = ArgList[0])) { rfc1459_odd(from, comm, ArgList); goto END; } cant_join_channel(ArgList[0], from_server); break; } } /* DEFAULT OFFER */ /* * This is the "default hook" case, where we offer to the user all of * the numerics that were not offered above. We simply catenate * all of the arguments into a string and offer to the user. * If the user bites, then we skip the "default display" section. */ copy = alloca(IRCD_BUFFER_SIZE + 1); *copy = 0; for (i = 0; ArgList[i]; i++) { if (i) strlcat(copy, " ", IRCD_BUFFER_SIZE); strlcat(copy, ArgList[i], IRCD_BUFFER_SIZE); } if (!do_hook(current_numeric, "%s %s", from, copy)) goto END; DISPLAY: /* DEFAULT DISPLAY */ /* * This is the "default display" case, where if the user does not * hook the numeric, we output the message in some special way. * If a numeric does not require special outputting, then we will * just display it with ``display_msg'' */ switch (numeric) { case 221: /* #define RPL_UMODEIS 221 */ { const char *umode; PasteArgs(ArgList, 0); if (!(umode = ArgList[0])) { rfc1459_odd(from, comm, ArgList); goto END; } put_it("%s Your user mode is \"%s\"", banner(), umode); break; } case 271: /* #define SILENCE_LIST 271 */ { const char *perp, *victim; PasteArgs(ArgList, 1); if (!(perp = ArgList[0])) { rfc1459_odd(from, comm, ArgList); goto END; } if (!(victim = ArgList[1])) { rfc1459_odd(from, comm, ArgList); goto END; } put_it("%s %s is ignoring %s", banner(), perp, victim); break; } case 301: /* #define RPL_AWAY 301 */ { const char *nick, *message; PasteArgs(ArgList, 1); if (!(nick = ArgList[0])) { rfc1459_odd(from, comm, ArgList); goto END; } if (!(message = ArgList[1])) { rfc1459_odd(from, comm, ArgList); goto END; } put_it("%s %s is away: %s", banner(), nick, message); break; } case 311: /* #define RPL_WHOISUSER 311 */ { const char *nick, *user, *host, *channel, *name; PasteArgs(ArgList, 4); if (!(nick = ArgList[0])) { rfc1459_odd(from, comm, ArgList); goto END; } if (!(user = ArgList[1])) { rfc1459_odd(from, comm, ArgList); goto END; } if (!(host = ArgList[2])) { rfc1459_odd(from, comm, ArgList); goto END; } if (!(channel = ArgList[3])) { rfc1459_odd(from, comm, ArgList); goto END; } if (!(name = ArgList[4])) { rfc1459_odd(from, comm, ArgList); goto END; } put_it("%s %s is %s@%s (%s)", banner(), nick, user, host, name); break; } case 312: /* #define RPL_WHOISSERVER 312 */ { const char *nick, *server, *pithy; PasteArgs(ArgList, 2); if (!(nick = ArgList[0])) { rfc1459_odd(from, comm, ArgList); goto END; } if (!(server = ArgList[1])) { rfc1459_odd(from, comm, ArgList); goto END; } if (!(pithy = ArgList[2])) { rfc1459_odd(from, comm, ArgList); goto END; } put_it("%s on irc via server %s (%s)", banner(), server, pithy); break; } case 313: /* #define RPL_WHOISOPERATOR 313 */ { const char *nick, *message; PasteArgs(ArgList, 1); if (!(nick = ArgList[0])) { rfc1459_odd(from, comm, ArgList); goto END; } if (!(message = ArgList[1])) { rfc1459_odd(from, comm, ArgList); goto END; } put_it("%s %s %s", banner(), ArgList[0], ArgList[1]); break; } case 314: /* #define RPL_WHOWASUSER 314 */ { const char *nick, *user, *host, *unused, *name; PasteArgs(ArgList, 4); if (!(nick = ArgList[0])) { rfc1459_odd(from, comm, ArgList); goto END; } if (!(user = ArgList[1])) { rfc1459_odd(from, comm, ArgList); goto END; } if (!(host = ArgList[2])) { rfc1459_odd(from, comm, ArgList); goto END; } if (!(unused = ArgList[3])) { rfc1459_odd(from, comm, ArgList); goto END; } if (!(name = ArgList[4])) { rfc1459_odd(from, comm, ArgList); goto END; } put_it("%s %s was %s@%s (%s)",banner(), nick, user, host, name); break; } case 317: /* #define RPL_WHOISIDLE 317 */ { const char *nick, *idle_str, *startup_str; int idle; const char * unit; char startup_ctime[128]; if (!(nick = ArgList[0])) { rfc1459_odd(from, comm, ArgList); goto END; } if (!(idle_str = ArgList[1])) { rfc1459_odd(from, comm, ArgList); goto END; } if (!(startup_str = ArgList[2])) { /* No problem */; } *startup_ctime = 0; if (startup_str) /* Undernet/TS4 */ { time_t startup; if ((startup = atol(startup_str)) != 0) snprintf(startup_ctime, 128, ", signed on at %s", my_ctime(startup)); } if ((idle = atoi(idle_str)) > 59) { idle /= 60; unit = "minute"; } else unit = "second"; put_it ("%s %s has been idle %d %ss%s", banner(), nick, idle, unit, startup_ctime); break; } case 318: /* #define RPL_ENDOFWHOIS 318 */ { PasteArgs(ArgList, 0); if (get_int_var(SHOW_END_OF_MSGS_VAR)) display_msg(from, comm, ArgList); break; } case 319: /* #define RPL_WHOISCHANNELS 319 */ { const char *nick, *channels; PasteArgs(ArgList, 1); if (!(nick = ArgList[0])) { rfc1459_odd(from, comm, ArgList); goto END; } if (!(channels = ArgList[1])) { rfc1459_odd(from, comm, ArgList); goto END; } put_it("%s on channels: %s", banner(), channels); break; } case 321: /* #define RPL_LISTSTART 321 */ /* Our screwy 321 handling demands this. BAH! */ put_it("%s Channel Users Topic", banner()); break; case 322: /* #define RPL_LIST 322 */ { static char format[25]; static int last_width = -1; const char *channel, *user_cnt, *line; PasteArgs(ArgList, 2); if (!(channel = ArgList[0])) { rfc1459_odd(from, comm, ArgList); goto END; } if (!(user_cnt = ArgList[1])) { rfc1459_odd(from, comm, ArgList); goto END; } if (!(line = ArgList[2])) { rfc1459_odd(from, comm, ArgList); goto END; } /* Figure out how to display this to the user. */ if (last_width != get_int_var(CHANNEL_NAME_WIDTH_VAR)) { if ((last_width = get_int_var(CHANNEL_NAME_WIDTH_VAR))) snprintf(format, 25, "%%-%u.%us %%-5s %%s", (unsigned) last_width, (unsigned) last_width); else strlcpy(format, "%s\t%-5s %s", sizeof format); } if (*channel == '*') say(format, "Prv", user_cnt, line); else say(format, check_channel_type(channel), user_cnt, line); break; } case 324: /* #define RPL_CHANNELMODEIS 324 */ { const char *mode, *channel; PasteArgs(ArgList, 1); if (!(channel = ArgList[0])) { rfc1459_odd(from, comm, ArgList); goto END; } if (!(mode = ArgList[1])) { rfc1459_odd(from, comm, ArgList); goto END; } put_it("%s Mode for channel %s is \"%s\"", banner(), channel, mode); break; } case 329: /* #define CREATION_TIME 329 */ { const char *channel, *time1_str, *time2_str, *time3_str; time_t time1, time2, time3; PasteArgs(ArgList, 2); if (!(channel = ArgList[0])) { rfc1459_odd(from, comm, ArgList); goto END; } if (!(time1_str = ArgList[1])) { rfc1459_odd(from, comm, ArgList); goto END; } if (!(time2_str = ArgList[2])) { /* No problem */; } if (!(time3_str = ArgList[3])) { /* No problem */; } /* Erf/TS4 support */ if (time2_str && time3_str) { time1 = (time_t)my_atol(time1_str); time2 = (time_t)my_atol(time2_str); time3 = (time_t)my_atol(time3_str); put_it("%s Channel %s was created at %ld, " "+c was last set at %ld, " "and has been opless since %ld", banner(), channel, time1, time2, time3); } else { time1 = (time_t)my_atol(time1_str); put_it("%s Channel %s was created at %s", banner(), channel, my_ctime(time1)); } break; } case 330: /* #define RPL_WHOISLOGGEDIN 330 */ { const char *nick, *login, *reason; PasteArgs(ArgList, 2); if (!(nick = ArgList[0])) { rfc1459_odd(from, comm, ArgList); goto END; } if (!(login = ArgList[1])) { rfc1459_odd(from, comm, ArgList); goto END; } if (!(reason = ArgList[2])) { reason = "is logged in as"; } put_it("%s %s %s %s", banner(), nick, reason, login); break; } case 332: /* #define RPL_TOPIC 332 */ { const char *channel, *topic; PasteArgs(ArgList, 1); if (!(channel = ArgList[0])) { rfc1459_odd(from, comm, ArgList); goto END; } if (!(topic = ArgList[1])) { rfc1459_odd(from, comm, ArgList); goto END; } put_it("%s Topic for %s: %s", banner(), channel, topic); break; } case 333: /* #define RPL_TOPICWHOTIME 333 */ { const char *channel, *nick, *when_str; time_t howlong; if (!(channel = ArgList[0])) { rfc1459_odd(from, comm, ArgList); goto END; } if (!(nick = ArgList[1])) { rfc1459_odd(from, comm, ArgList); goto END; } if (!(when_str = ArgList[2])) { rfc1459_odd(from, comm, ArgList); goto END; } howlong = time(NULL) - my_atol(when_str); put_it("%s The topic was set by %s %ld sec ago",banner(), nick, howlong); break; } case 341: /* #define RPL_INVITING 341 */ { const char *nick, *channel; if (!(nick = ArgList[0])) { rfc1459_odd(from, comm, ArgList); goto END; } if (!(channel = ArgList[1])) { rfc1459_odd(from, comm, ArgList); goto END; } message_from(channel, LOG_CRAP); put_it("%s Inviting %s to channel %s", banner(), nick, channel); break; } case 351: /* #define RPL_VERSION 351 */ { const char *version, *itsname, *stuff; PasteArgs(ArgList, 2); if (!(version = ArgList[0])) { rfc1459_odd(from, comm, ArgList); goto END; } if (!(itsname = ArgList[1])) { rfc1459_odd(from, comm, ArgList); goto END; } if (!(stuff = ArgList[2])) { rfc1459_odd(from, comm, ArgList); goto END; } put_it("%s Server %s: %s %s",banner(), itsname, version, stuff); break; } case 353: /* #define RPL_NAMREPLY 353 */ { static int last_width; char format[41]; const char *type, *channel, *line; PasteArgs(ArgList, 2); if (!(type = ArgList[0])) { rfc1459_odd(from, comm, ArgList); goto END; } if (!(channel = ArgList[1])) { rfc1459_odd(from, comm, ArgList); goto END; } if (!(line = ArgList[2])) { line = empty_string; } /* This is only for when the user joined the channel */ if (channel_is_syncing(channel, from_server)) { /* If the user bites on /ON NAMES, then skip the rest */ message_from(channel, LOG_CRAP); if (do_hook(NAMES_LIST, "%s %s", channel, line)) if (get_int_var(SHOW_CHANNEL_NAMES_VAR)) say("Users on %s: %s", check_channel_type(channel), line); break; } /* If the user grabs /ON NAMES then just stop right here */ if (!do_hook(NAMES_LIST, "%s %s", channel, line)) break; /* This all is for when the user has not just joined channel */ if (last_width != get_int_var(CHANNEL_NAME_WIDTH_VAR)) { if ((last_width = get_int_var(CHANNEL_NAME_WIDTH_VAR))) snprintf(format, 40, "%%s: %%-%u.%us %%s", (unsigned char) last_width, (unsigned char) last_width); else strlcpy(format, "%s: %s\t%s", sizeof format); } else strlcpy(format, "%s: %s\t%s", sizeof format); message_from(channel, LOG_CRAP); if (*type == '=') { if (last_width && ((int)strlen(channel) > last_width)) { char *channel_copy = LOCAL_COPY(channel); channel_copy[last_width-1] = '>'; channel_copy[last_width] = 0; channel = channel_copy; } put_it(format, "Pub", check_channel_type(channel), line); } else if (*type == '*') put_it(format, "Prv", check_channel_type(channel), line); else if (*type == '@') put_it(format, "Sec", check_channel_type(channel), line); break; } case 364: /* #define RPL_LINKS 364 */ { const char *itsname, *uplink, *stuff; PasteArgs(ArgList, 2); if (!(itsname = ArgList[0])) { rfc1459_odd(from, comm, ArgList); goto END; } if (!(uplink = ArgList[1])) { rfc1459_odd(from, comm, ArgList); goto END; } if (!(stuff = ArgList[2])) { stuff = empty_string; } if (stuff) put_it("%s %-20s %-20s %s", banner(), itsname, uplink, stuff); else put_it("%s %-20s %s", banner(), itsname, uplink); break; } case 366: /* #define RPL_ENDOFNAMES 366 */ { const char *channel; if (!get_int_var(SHOW_END_OF_MSGS_VAR)) break; if (!(channel = ArgList[0])) { rfc1459_odd(from, comm, ArgList); goto END; } if (!channel_is_syncing(channel, from_server)) display_msg(from, comm, ArgList); break; } case 346: /* +I on erf */ case 348: /* +e on erf */ case 367: /* +b */ { const char *channel, *ban, *perp, *when_str; time_t howlong; if (!(channel = ArgList[0])) { rfc1459_odd(from, comm, ArgList); goto END; } if (!(ban = ArgList[1])) { rfc1459_odd(from, comm, ArgList); goto END; } if (!(perp = ArgList[2])) { /* No problem. */ } if (!(when_str = ArgList[3])) { /* No problem. */ } if (perp && when_str) { howlong = time(NULL) - my_atol(when_str); put_it("%s %s %-25s set by %-10s %ld sec ago", banner(), channel, ban, perp, howlong); } else put_it("%s %s %s", banner(), channel, ban); break; } case 401: /* #define ERR_NOSUCHNICK 401 */ { const char *nick, *stuff; PasteArgs(ArgList, 1); if (!(nick = ArgList[0])) { rfc1459_odd(from, comm, ArgList); goto END; } if (!(stuff = ArgList[1])) { rfc1459_odd(from, comm, ArgList); goto END; } put_it("%s %s: %s", banner(), nick, stuff); break; } case 219: /* #define RPL_ENDOFSTATS 219 */ case 232: /* #define RPL_ENDOFSERVICES 232 */ case 365: /* #define RPL_ENDOFLINKS 365 */ case 369: /* #define RPL_ENDOFWHOWAS 369 */ case 374: /* #define RPL_ENDOFINFO 374 */ case 394: /* #define RPL_ENDOFUSERS 394 */ { PasteArgs(ArgList, 0); if (get_int_var(SHOW_END_OF_MSGS_VAR)) display_msg(from, comm, ArgList); break; } case 471: /* #define ERR_CHANNELISFULL 471 */ { const char *message; PasteArgs(ArgList, 0); if (!(message = ArgList[0])) { rfc1459_odd(from, comm, ArgList); goto END; } put_it("%s %s (Channel is full)", banner(), message); break; } case 473: /* #define ERR_INVITEONLYCHAN 473 */ { const char *message; PasteArgs(ArgList, 0); if (!(message = ArgList[0])) { rfc1459_odd(from, comm, ArgList); goto END; } put_it("%s %s (You must be invited)", banner(), message); break; } case 474: /* #define ERR_BANNEDFROMCHAN 474 */ { const char *message; PasteArgs(ArgList, 0); if (!(message = ArgList[0])) { rfc1459_odd(from, comm, ArgList); goto END; } put_it("%s %s (You are banned)", banner(), message); break; } case 475: /* #define ERR_BADCHANNELKEY 475 */ { const char *message; PasteArgs(ArgList, 0); if (!(message = ArgList[0])) { rfc1459_odd(from, comm, ArgList); goto END; } put_it("%s %s (You must give the correct key)", banner(), message); break; } case 476: /* #define ERR_BADCHANMASK 476 */ { const char *message; PasteArgs(ArgList, 0); if (!(message = ArgList[0])) { rfc1459_odd(from, comm, ArgList); goto END; } put_it("%s %s (Bad channel mask)", banner(), message); break; } case 477: /* #define ERR_NEEDREGGEDNICK 477 */ { const char *message; PasteArgs(ArgList, 0); if (!(message = ArgList[0])) { rfc1459_odd(from, comm, ArgList); goto END; } /* IRCnet has a different 477 numeric. */ if (message && *message == '+') { display_msg(from, comm, ArgList); break; } PasteArgs(ArgList, 0); put_it("%s %s (You must use a registered nickname)", banner(), message); break; } default: display_msg(from, comm, ArgList); } END: /* * This is where we clean up after our numeric. Numeric-specific * cleanups can occur here, and then below we reset the display * settings. */ switch (numeric) { case 347: /* #define END_OF_INVITELIST */ case 349: /* #define END_OF_EXCEPTLIST */ case 368: number_of_bans = 0; break; case 464: /* #define ERR_PASSWDMISMATCH 464 */ { char server_num[8]; if (oper_command) oper_command = 0; else if (!is_server_registered(from_server)) { server_reconnects_to(from_server, NOSERV); say("Password required for connection to server %s", get_server_name(from_server)); if (!dumb_mode) { strlcpy(server_num, ltoa(from_server), sizeof server_num); add_wait_prompt("Server Password:", password_sendline, server_num, WAIT_PROMPT_LINE, 0); } } } } current_numeric = old_current_numeric; set_lastlog_msg_level(lastlog_level); message_from(NULL, LOG_CRAP); }
void io (const char *what) { static int first_time = 1; long clock_timeout = 0, timer_timeout = 0, real_timeout = 0; static struct timeval my_now, my_timer, *time_ptr = &my_timer; int hold_over, rc; fd_set rd, wd; get_time(&my_now); now = my_now.tv_sec; /* CHECK FOR CPU SAVER MODE */ if (!cpu_saver && get_int_var(CPU_SAVER_AFTER_VAR)) if (now - idle_time > get_int_var(CPU_SAVER_AFTER_VAR) * 60) cpu_saver_on(0, NULL); rd = readables; wd = writables; FD_ZERO(&wd); FD_ZERO(&rd); set_screens(&rd, &wd); set_server_bits(&rd, &wd); set_process_bits(&rd); set_socket_read(&rd, &wd); icmp_sockets(&rd, &wd); #if defined(WANT_THREAD) #ifdef WANT_NSLOOKUP set_dns_output_fd(&rd); #endif #ifdef WANT_PTEST set_ptest_output_fd(&rd); #endif #ifdef WANT_MP3PLAYER set_mp3_output_fd(&rd); #endif # if defined(GTK) if (tgtk_okay()) tgtk_set_output_fd(&rd); # endif #endif clock_timeout = (timeout_select - (my_now.tv_sec % timeout_select)) * 1000; if (cpu_saver && get_int_var(CPU_SAVER_EVERY_VAR)) clock_timeout += (get_int_var(CPU_SAVER_EVERY_VAR) - 1) * 60000; timer_timeout = TimerTimeout(); if ((hold_over = unhold_windows())) real_timeout = 0; else if (timer_timeout <= clock_timeout) real_timeout = timer_timeout; else real_timeout = clock_timeout; if (real_timeout == -1) time_ptr = NULL; else { time_ptr->tv_sec = real_timeout / 1000; time_ptr->tv_usec = ((real_timeout % 1000) * 1000); } /* GO AHEAD AND WAIT FOR SOME DATA TO COME IN */ switch ((rc = new_select(&rd, &wd, time_ptr))) { case 0: break; case -1: { /* if we just got a sigint */ first_time = 0; if (cntl_c_hit) edit_char('\003'); else if (errno && errno != EINTR) { int ii = 0; fd_set rd1, wd1; char ii_buff_r[500]; char ii_buff_w[500]; int ii_r[FD_SETSIZE]; int ii_w[FD_SETSIZE]; yell("Select failed with [%d:%s]", errno, strerror(errno)); /* Reseed fd_sets so we can dig further */ yell("Packing fd_sets... Dump of fd's set in fd_set"); ii_buff_r[0] = '\0'; ii_buff_w[0] = '\0'; for (ii = 0; ii < FD_SETSIZE; ii++) { ii_r[ii] = 0; ii_w[ii] = 0; } FD_ZERO(&wd1); FD_ZERO(&rd1); set_screens(&rd1, &wd1); set_server_bits(&rd1, &wd1); set_process_bits(&rd1); set_socket_read(&rd1, &wd1); icmp_sockets(&rd1, &wd1); #if defined(WANT_THREAD) #ifdef WANT_NSLOOKUP set_dns_output_fd(&rd1); #endif #ifdef WANT_PTEST set_ptest_output_fd(&rd1); #endif #ifdef WANT_MP3PLAYER set_mp3_output_fd(&rd1); #endif # if defined(GTK) if (tgtk_okay()) tgtk_set_output_fd(&rd1); # endif #endif for (ii = 0; ii <= global_max_fd; ii++) { fd_set rblah, wblah; memcpy(&rblah, &rd1, sizeof(fd_set)); FD_SET(ii, &rblah); if (memcmp(&rblah, &rd1, sizeof(fd_set)) == 0) { char blahblah[20]; sprintf(blahblah, "%d ", ii); strcat(ii_buff_r, blahblah); ii_r[ii] = 1; } memcpy(&wblah, &wd1, sizeof(fd_set)); FD_SET(ii, &wblah); if (memcmp(&wblah, &wd1, sizeof(fd_set)) == 0) { char blahblah[20]; yell("blah"); sprintf(blahblah, "%d ", ii); strcat(ii_buff_w, blahblah); ii_w[ii] = 1; } } yell("Read fd's in set: %s", (ii_buff_r[0] == '\0') ? "<NONE>" : ii_buff_r); for (ii = 0; ii <= global_max_fd; ii++) { if (ii_r[ii] == 1) { struct stat st; if (fstat(ii, &st) == -1) { yell("READ FD %d is causing the select failure!", ii); } else { if (S_ISSOCK(st.st_mode)) yell("READ FD %d is a socket!", ii); else if (S_ISREG(st.st_mode)) yell("READ FD %d is a regular file!", ii); else if (S_ISFIFO(st.st_mode)) yell("READ FD %d is a FIFO!", ii); else ; } } } yell("Write fd's in set: %s", (ii_buff_w[0] == '\0') ? "<NONE>" : ii_buff_w); for (ii = 0; ii <= global_max_fd; ii++) { if (ii_w[ii] == 1) { struct stat st; if (fstat(ii, &st) == -1) { yell("WRITE FD %d is causing the select failure!", ii); } else { if (S_ISSOCK(st.st_mode)) yell("WRITE FD %d is a socket!", ii); else if (S_ISREG(st.st_mode)) yell("WRITE FD %d is a regular file!", ii); else if (S_ISFIFO(st.st_mode)) yell("WRITE FD %d is a FIFO!", ii); else ; } } } sleep(10); } else { #if 0 yell("errno 0 rc = -1, maybe it'll go away"); sleep(10); #endif } break; } /* we got something on one of the descriptors */ default: { cntl_c_hit = 0; now = time(NULL); make_window_current(NULL); do_screens(&rd); check_icmpresult(&rd, &wd); #if defined(WANT_THREAD) #ifdef WANT_NSLOOKUP dns_check(&rd); #endif #ifdef WANT_PTEST ptest_check(&rd); #endif #ifdef WANT_MP3PLAYER mp3_check(&rd); #endif # if defined(GTK) if (tgtk_okay()) tgtk_check(&rd); # endif #endif do_server(&rd, &wd); do_processes(&rd); scan_sockets(&rd, &wd); clean_sockets(); break; } } now = time(NULL); ExecuteTimers(); get_child_exit(-1); if (update_refresh) { update_refresh = 0; refresh_screen(0, NULL); } if (!hold_over) cursor_to_input(); if (update_clock(RESET_TIME)) { if (get_int_var(CLOCK_VAR)) { update_all_status(current_window, NULL, 0); cursor_to_input(); } clean_queue(get_int_var(TRANSFER_TIMEOUT_VAR)); /* timeout if send time is greater than 5 minutes */ } /* (set in term.c) -- we should redraw the screen here */ if (need_redraw) refresh_screen(0, NULL); #ifdef WANT_THREAD if (scan_done) scan_is_done(); #endif alloca(0); return; }
/* * do_ctcp: a re-entrant form of a CTCP parser. The old one was lame, * so i took a hatchet to it so it didnt suck. * * XXXX - important! The third argument -- 'str', is expected to be * 'BIG_BUFFER_SIZE + 1' or larger. If it isnt, chaos will probably * ensue if you get spammed with lots of CTCP UTC requests. * * UTC requests can be at minimum 5 bytes, and the expansion is always 24. * That means you can cram (510 - strlen("PRIVMSG x :") / 5) UTCs (100) * into a privmsg. That means itll expand to 2400 characters. We silently * limit the number of valid CTCPs to 4. Anything more than that we dont * even bother with. (4 * 24 + 11 -> 106), which is less than * IRCD_BUFFER_SIZE, which gives us plenty of safety. * * XXXX - The normal way of implementation required two copies -- once into a * temporary buffer, once back into the original buffer -- for the best case * scenario. This is horrendously inefficient, since most privmsgs dont * contain any CTCPs. So we check to see if there are any CTCPs in the * message before we bother doing anything. THIS IS AN INELEGANT HACK! * But the call to charcount() is less expensive than even one copy to * strlcpy() since they both evaluate *each* character, and charcount() * doesnt have to do a write unless the character is present. So it is * definitely worth the cost to save CPU time for 99% of the PRIVMSGs. */ char * do_ctcp (const char *from, const char *to, char *str) { int flag; int fflag; char local_ctcp_buffer [BIG_BUFFER_SIZE + 1], the_ctcp [IRCD_BUFFER_SIZE + 1], last [IRCD_BUFFER_SIZE + 1]; char *ctcp_command, *ctcp_argument; int i; char *ptr = NULL; int allow_ctcp_reply = 1; static time_t last_ctcp_parsed = 0; int l; char * extra = NULL; int delim_char = charcount(str, CTCP_DELIM_CHAR); if (delim_char < 2) return str; /* No CTCPs. */ if (delim_char > 8) allow_ctcp_reply = 0; /* Historical limit of 4 CTCPs */ flag = check_ignore_channel(from, FromUserHost, to, LEVEL_CTCP); fflag = new_check_flooding(from, FromUserHost, is_channel(to) ? to : NULL, str, LEVEL_CTCP); in_ctcp_flag++; strlcpy(local_ctcp_buffer, str, sizeof(local_ctcp_buffer) - 2); for (;;strlcat(local_ctcp_buffer, last, sizeof(local_ctcp_buffer) - 2)) { if (split_CTCP(local_ctcp_buffer, the_ctcp, last)) break; /* All done! */ if (!*the_ctcp) continue; /* Empty requests are ignored */ /* * Apply some integrety rules: * -- If we've already replied to a CTCP, ignore it. * -- If user is ignoring sender, ignore it. * -- If we're being flooded, ignore it. * -- If CTCP was a global msg, ignore it. */ /* * Yes, this intentionally ignores "unlimited" CTCPs like * UTC and SED. Ultimately, we have to make sure that * CTCP expansions dont overrun any buffers that might * contain this string down the road. So by allowing up to * 4 CTCPs, we know we cant overflow -- but if we have more * than 40, it might overflow, and its probably a spam, so * no need to shed tears over ignoring them. Also makes * the sanity checking much simpler. */ if (!allow_ctcp_reply) continue; /* * Check to see if the user is ignoring person. * Or if we're suppressing a flood. */ if (flag == IGNORED || fflag == 1) { if (x_debug & DEBUG_CTCPS) yell("CTCP from [%s] ignored", from); allow_ctcp_reply = 0; continue; } /* * Check for CTCP flooding */ if (get_int_var(NO_CTCP_FLOOD_VAR)) { if (time(NULL) - last_ctcp_parsed < 2) { /* * This extends the flood protection until * we dont get a CTCP for 2 seconds. */ last_ctcp_parsed = time(NULL); allow_ctcp_reply = 0; if (x_debug & DEBUG_CTCPS) say("CTCP flood from [%s] ignored", from); continue; } } /* * Check for global message */ if (*to == '$' || (*to == '#' && !im_on_channel(to, from_server))) { allow_ctcp_reply = 0; continue; } /* * Now its ok to parse the CTCP. * First we remove the argument. * XXX - CTCP spec says word delim MUST be space. */ ctcp_command = the_ctcp; ctcp_argument = strchr(the_ctcp, ' '); if (ctcp_argument) *ctcp_argument++ = 0; else ctcp_argument = endstr(the_ctcp); /* Set up the window level/logging */ if (im_on_channel(to, from_server)) l = message_from(to, LEVEL_CTCP); else l = message_from(from, LEVEL_CTCP); /* * Then we look for the correct CTCP. */ for (i = 0; i < NUMBER_OF_CTCPS; i++) if (!strcmp(ctcp_command, ctcp_cmd[i].name)) break; /* * We didnt find it? */ if (i == NUMBER_OF_CTCPS) { /* * Offer it to the user. * Maybe they know what to do with it. */ if (do_hook(CTCP_REQUEST_LIST, "%s %s %s %s", from, to, ctcp_command, ctcp_argument)) { if (do_hook(CTCP_LIST, "%s %s %s %s", from, to, ctcp_command, ctcp_argument)) { say("Unknown CTCP %s from %s to %s: %s%s", ctcp_command, from, to, *ctcp_argument ? ": " : empty_string, ctcp_argument); } } time(&last_ctcp_parsed); allow_ctcp_reply = 0; pop_message_from(l); continue; } /* * rfc1459_any_to_utf8 specifically ignores CTCPs, because * recoding binary data (such as an encrypted message) would * corrupt the message. * * So some CTCPs are "recodable" and some are not. * * The CTCP_NORECODE is set for any CTCPs which are NOT * to be recoded prior to handling. These are the encryption * CTCPS. * * All other CTCPs have not been recoded by the time they * reach here, so we must do it here! */ if (!(ctcp_cmd[i].flag & CTCP_NORECODE)) { /* * We must recode to UTF8 */ inbound_recode(from, from_server, to, ctcp_argument, &extra); if (extra) ctcp_argument = extra; } /* * We did find it. Acknowledge it. */ ptr = NULL; if (do_hook(CTCP_REQUEST_LIST, "%s %s %s %s", from, to, ctcp_command, ctcp_argument)) { ptr = ctcp_cmd[i].func(ctcp_cmd + i, from, to, ctcp_argument); } /* * If this isnt an 'unlimited' CTCP, set up flood protection. * * No, this wont allow users to flood any more than they * would normally. The UTC/SED gets converted into a * regular privmsg body, which is flagged via FLOOD_PUBLIC. */ if (!(ctcp_cmd[i].flag & CTCP_NOLIMIT)) { time(&last_ctcp_parsed); allow_ctcp_reply = 0; } /* * We've only gotten to this point if its a valid CTCP * query and we decided to parse it. */ /* * If its an ``INLINE'' CTCP, we paste it back in. */ if (ctcp_cmd[i].flag & CTCP_INLINE) strlcat(local_ctcp_buffer, ptr ? ptr : empty_string, sizeof local_ctcp_buffer); /* * If its ``INTERESTING'', tell the user. * Note that this isnt mutex with ``INLINE'' in theory, * even though it is in practice. Dont use 'else' here. */ if (ctcp_cmd[i].flag & CTCP_TELLUSER) { if (do_hook(CTCP_LIST, "%s %s %s %s", from, to, ctcp_command, ctcp_argument)) { if (is_me(from_server, to)) say("CTCP %s from %s%s%s", ctcp_command, from, *ctcp_argument ? ": " : empty_string, ctcp_argument); else say("CTCP %s from %s to %s%s%s", ctcp_command, from, to, *ctcp_argument ? ": " : empty_string, ctcp_argument); } } new_free(&extra); new_free(&ptr); pop_message_from(l); } in_ctcp_flag--; /* * 'str' is required to be BIG_BUFFER_SIZE + 1 or bigger per the API. */ strlcpy(str, local_ctcp_buffer, BIG_BUFFER_SIZE); return str; }
/* * NAME: client_connect * USAGE: Create a new socket and establish both endpoints with the * arguments given. * ARGS: l - A local sockaddr structure representing the local side of * the connection. NULL is permitted. If this value is NULL, * then the local side of the connection will not be bind()ed. * ll - The sizeof(l) -- if 0, then 'l' is treated as a NULL value. * r - A remote sockaddr structure representing the remote side of * the connection. NULL is not permitted. * rl - The sizeof(r) -- if 0, then 'r' is treated as a NULL value. * Therefore, 0 is not permitted. */ int client_connect (SA *l, socklen_t ll, SA *r, socklen_t rl) { int fd = -1; int family = AF_UNSPEC; if (ll == 0) l = NULL; if (rl == 0) r = NULL; if (!r) { syserr(-1, "client_connect: remote addr missing (connect to who?)"); return -1; } if (l && r && l->sa_family != r->sa_family) { syserr(-1, "client_connect: local addr protocol (%d) is different " "from remote addr protocol (%d)", l->sa_family, r->sa_family); return -1; } if (l) family = l->sa_family; if (r) family = r->sa_family; if ((fd = Socket(family, SOCK_STREAM, 0)) < 0) { syserr(-1, "client_connect: socket(%d) failed: %s", family, strerror(errno)); return -1; } if (family == AF_UNIX || family == AF_INET #ifdef INET6 || family == AF_INET6 #endif ) { if (l && bind(fd, l, ll)) { syserr(-1, "client_connect: bind(%d) failed: %s", fd, strerror(errno)); close(fd); return -1; } if (Connect(fd, r)) { syserr(-1, "client_connect: connect(%d) failed: %s", fd, strerror(errno)); close(fd); return -1; } } else { syserr(-1, "client_connect: protocol (%d) not supported", family); return -1; } if (x_debug & DEBUG_SERVER_CONNECT) yell("Connected on des [%d]", fd); return fd; }
/* * do_notice_ctcp: a re-entrant form of a CTCP reply parser. * See the implementation notes in do_ctcp(). */ char * do_notice_ctcp (const char *from, const char *to, char *str) { int flag; char local_ctcp_buffer [BIG_BUFFER_SIZE + 1], the_ctcp [IRCD_BUFFER_SIZE + 1], last [IRCD_BUFFER_SIZE + 1]; char *ctcp_command, *ctcp_argument; int i; char *ptr; int allow_ctcp_reply = 1; int l; int delim_char = charcount(str, CTCP_DELIM_CHAR); if (delim_char < 2) return str; /* No CTCPs. */ if (delim_char > 8) allow_ctcp_reply = 0; /* Ignore all the CTCPs. */ /* We handle ignore, but not flooding (obviously) */ flag = check_ignore_channel(from, FromUserHost, to, LEVEL_CTCP); in_ctcp_flag++; strlcpy(local_ctcp_buffer, str, sizeof(local_ctcp_buffer) - 2); for (;;strlcat(local_ctcp_buffer, last, sizeof(local_ctcp_buffer) - 2)) { if (split_CTCP(local_ctcp_buffer, the_ctcp, last)) break; /* All done! */ if (!*the_ctcp) continue; /* Empty requests are ignored */ /* * The logic of all this is essentially the same as * do_ctcp */ if (!allow_ctcp_reply) continue; if (flag == IGNORED) { if (x_debug & DEBUG_CTCPS) yell("CTCP REPLY from [%s] ignored", from); allow_ctcp_reply = 0; continue; } /* But we don't check ctcp flooding (obviously) */ /* Global messages -- just drop the CTCP */ if (*to == '$' || (is_channel(to) && !im_on_channel(to, from_server))) { allow_ctcp_reply = 0; continue; } /* * Parse CTCP message * CTCP spec says word delim MUST be space */ ctcp_command = the_ctcp; ctcp_argument = strchr(the_ctcp, ' '); if (ctcp_argument) *ctcp_argument++ = 0; else ctcp_argument = endstr(the_ctcp); /* Set up the window level/logging */ if (is_channel(to)) l = message_from(to, LEVEL_CTCP); else l = message_from(from, LEVEL_CTCP); /* * Find the correct CTCP and run it. */ for (i = 0; i < NUMBER_OF_CTCPS; i++) if (!strcmp(ctcp_command, ctcp_cmd[i].name)) break; /* * If its a built in CTCP command, check to see if its * got a reply handler, call if appropriate. */ if (i < NUMBER_OF_CTCPS && ctcp_cmd[i].repl) { if ((ptr = ctcp_cmd[i].repl(ctcp_cmd + i, from, to, ctcp_argument))) { strlcat(local_ctcp_buffer, ptr, sizeof local_ctcp_buffer); new_free(&ptr); pop_message_from(l); continue; } } /* Toss it at the user. */ if (ctcp_cmd[i].flag & CTCP_TELLUSER) { if (do_hook(CTCP_REPLY_LIST, "%s %s %s %s", from, to, ctcp_command, ctcp_argument)) say("CTCP %s reply from %s: %s", ctcp_command, from, ctcp_argument); } if (!(ctcp_cmd[i].flag & CTCP_NOLIMIT)) allow_ctcp_reply = 0; pop_message_from(l); } in_ctcp_flag--; /* * local_ctcp_buffer is derived from 'str', so its always * smaller or equal in size to 'str', so this copy is safe. */ strlcpy(str, local_ctcp_buffer, BIG_BUFFER_SIZE); return str; }