Example #1
0
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);
}
Example #2
0
/*
 * 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;
}
Example #3
0
File: if.c Project: choppsv1/ircii
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);
}
Example #4
0
/*
 * 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;
}
Example #5
0
File: files.c Project: tcava/bx2
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;
}
Example #6
0
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);
}
Example #7
0
/*
 * 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);
}
Example #8
0
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() );
}
Example #9
0
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;
}
Example #10
0
File: exec.c Project: srfrog/epic5
/*
 * 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);
}
Example #11
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() );
}
Example #12
0
/*
 * 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);
}
Example #13
0
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() );
	}
}
Example #14
0
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);
}
Example #15
0
int main() {
    int a = 0;
    printf("%d %d",a,yell(2));
    return 0;
}
Example #16
0
File: if.c Project: choppsv1/ircii
/*  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);
}
Example #17
0
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;
}
Example #18
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;
}
Example #19
0
File: if.c Project: choppsv1/ircii
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);
}
Example #20
0
/*
 * '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;
}
Example #21
0
static VALUE epic_echo (VALUE module, VALUE string)
{
	RUBY_STARTUP
	yell("%s", my_string);
	return Qnil;
}
Example #22
0
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);
}
Example #23
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;
}
Example #24
0
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;
}
Example #25
0
/*
 * 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();
}
Example #26
0
/*
 * 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);
}
Example #27
0
File: main.c Project: jnbek/TekNap
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;
}
Example #28
0
File: ctcp.c Project: srfrog/epic5
/*
 * 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;
}
Example #29
0
/*
 * 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;
}
Example #30
0
File: ctcp.c Project: srfrog/epic5
/*
 * 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;
}