590 lines · 12.8 KB · C
RawDownload
/* * ------------------------------------------------------- * Copyright (C) 2003-2007 Tommi Saviranta <wnd@iki.fi> *      (C) 2002 Lee Hardy <lee@leeh.co.uk> *      (C) 1998-2002 Sebastian Kienzl <zap@riot.org> * ------------------------------------------------------- * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the * GNU General Public License for more details. */ #ifdef HAVE_CONFIG_H#include <config.h>#endif /* ifdef HAVE_CONFIG_H */ #include "client.h"#include "conntype.h"#include "error.h"#include "messages.h"#include "miau.h"#include "irc.h"#include "qlog.h"#include "tools.h"#include "channels.h"#include "dcc.h"#include "privlog.h"#include "commands.h"#include "chanlog.h"#include "log.h"#include "common.h" #include <string.h>   client_info	i_client;clientlist_type	c_clients;  void client_drop_real(connection_type *client, char *reason,		const int echo, const int dying);   /* * "work" must be global so when miau_command is called, "work" can be freed * if users want to quit miau. */static char *work = NULL;	/* Temporary copy of input. */   /* * Drop client from bouncer. * * If client == NULL, drop all clients. */voidclient_drop(connection_type *client, char *reason, const int msgtype,		const int echo, const char *awaymsg){	if (client == NULL) {		/* Drop all clients. */		while (c_clients.clients->head != NULL) {			client_drop_real((connection_type *)					c_clients.clients->head->data, reason,					echo, msgtype == DISCONNECT_DYING);		}	} else {		client_drop_real(client, reason, echo,				msgtype == DISCONNECT_DYING);	} 	switch (msgtype) {		case DISCONNECT_ERROR:			error("%s", reason);			break;		case DISCONNECT_DYING:			report("%s%s", CLNT_DIE, reason);			break;		case DISCONNECT_REPORT:			report("%s", reason);			break;	} 	/* Reporting number of clients is irrevelant if only one is allowed. */	if (cfg.maxclients != 1) {		report(CLNT_CLIENTS, c_clients.connected);	} 	if (c_clients.connected == 0) {		clients_left(cfg.usequitmsg ? awaymsg : NULL);	} else if (cfg.autoaway == 1) {		if (cfg.usequitmsg == 1 && awaymsg != NULL){			set_away(awaymsg);		} else {			set_away(cfg.awaymsg);		}	}} /* void client_drop(connection_type *, char *, const int, const int,	const char *) */   /* * Drop client from bouncer. */voidclient_drop_real(connection_type *client, char *reason, const int echo,		const int dying){	llist_node	*node;	/* We could skip testing reason, but lets play safe. */	if (echo && reason != NULL) {		/* Set back to blocking. */		sock_setblock(c_server.socket);		if (reason[0] == ':') {			irc_write(client, "ERROR %s", reason);		} else {			irc_write(client, dying					? MIAU_USERKILLED : MIAU_CLOSINGLINK,					reason);		}	}	sock_close(client);	node = llist_find((void *) client, c_clients.clients);	xfree(node->data);	llist_delete(node, c_clients.clients);	c_clients.connected--;} /* void client_drop_real(connection_type *, char *, const int, const int) */   static voidcmd_part_action(channel_type *chan, char *reason){	/*	 * ":" is always there after channel name so this works even with	 * mIRC when connected to Undernet.	 */	irc_mwrite(&c_clients, ":%s!%s@%s PART %s :%s",			status.nickname, i_client.username, i_client.hostname,			chan->name, reason);	channel_rem(chan, LIST_PASSIVE);}   static voidcmd_part(char *par0, char *par1){	/* User wants to leave list of channels. */	channel_type *chan;	char *name; 	name = strtok(par0, ":");	/* Set EOS for channels. */	name = strtok(par0, ",");	while (name != NULL) {		chan = channel_find(name, LIST_PASSIVE);		if (chan == NULL) {			irc_mwrite(&c_clients, ":miau %d %s %s :%s",					ERR_NOSUCHCHANNEL,					status.nickname,					name,					IRC_NOSUCHCHAN);		} else {			cmd_part_action(chan, par1 + 1);		}		name = strtok(NULL, ",");	}} /* static void cmd_part(char *par0, char *par1) */   static voidcmd_join(char *par0, char *par1){	/* user wants to join a list of channels */	char *chan;	/* channel name */	char *key;	/* channel key */	char *chanseek;	char *keyseek; 	if (par0 != NULL && xstrcmp(par0, "0") == 0) {		/* user want to leave all channels */		LLIST_WALK_H(passive_channels.head, channel_type *);			cmd_part_action(data, "");		LLIST_WALK_F; 		return;	} 	chan = par0;	key = par1;	keyseek = NULL; 	while (chan != NULL && *chan != '\0') {		chanseek = strchr(chan, ',');		if (chanseek != NULL) {			*chanseek = '\0';			chanseek++;		}		if (key != NULL && *key != '\0') {			keyseek = strchr(key, ',');			if (keyseek != NULL) {				*keyseek = '\0';				keyseek++;			}		}		irc_mnotice(&c_clients, status.nickname,				MIAU_JOIN_QUEUE, chan);		channel_add(chan, key, LIST_PASSIVE);		chan = chanseek;		key = keyseek;	}} /* static void cmd_join(char *par0, char *par1) */   #ifdef DCCBOUNCEstatic intcmd_privmsg_ctcp(char *par0, char *par1){	char dcct[IRC_MSGLEN];	char *ret; 	if (cfg.dccbounce == 0) {		return 1;	} 	upcase(par1);	if (xstrncmp(par1, ":\1DCC", 5) != 0) {		return 1;	} 	strncpy(dcct, par1 + 1, IRC_MSGLEN);	ret = dcc_initiate(dcct, IRC_MSGLEN, 1); 	if (ret != NULL) {		irc_write(&c_server, "PRIVMSG %s %s", par0, dcct);		return 0;	} else {		return 1;	}} /* static int cmd_privmsg_dcc(char *par0, char *par1) */#endif /* ifdef DCCBOUNCE */   #ifdef NEED_LOGGINGstatic intcmd_privmsg(char *par0, char *par1){	int is_chan;	if (par0 == NULL) {		return 1;	} 	is_chan = channel_is_name(par0); #ifdef PRIVLOG	if (is_chan == 0) {		/*		 * We could say		 *		if ((c_clients.connected > 0 && (cfg.privlog & 0x02))				|| (c_clients.connected == 0					&& cfg.privlog == PRIVLOG_DETACHED)) {		 *		 * ...but do disconnected clients really talk?-)		 *		 * Therefore we say the following instead:		 */		if (cfg.privlog != 0) {			privlog_write(par0, PRIVLOG_OUT,					CMD_PRIVMSG + MINCOMMANDVALUE,					par1 + 1);		}	}#endif /* PRIVLOG */ #ifdef CHANLOG	if (is_chan != 0) {		channel_type *chan;		chan = channel_find(par0, LIST_ACTIVE);		if (chan != NULL && chanlog_has_log(chan, LOG_MESSAGE)) {			char *t;			t = log_prepare_entry(status.nickname, par1 + 1);			if (t == NULL) {				chanlog_write_entry(chan, LOGM_MESSAGE,						get_short_localtime(),						status.nickname, par1 + 1);			} else {				chanlog_write_entry(chan, "%s", t);			}		}	}#endif /* CHANLOG */ 	return 1;} /* static int cmd_privmsg(char *par0, char *par1) */#endif /* ifdef NEED_LOGGING */   static intcmd_away(const char *orig, char *par0, char *par1){	if (par0 == NULL) {		FREE(status.awaymsg);		/* Not away / no custom message. */		status.awaystate &= ~AWAY & ~CUSTOM;	} else {		/* This should be safe by now. */		char *t = strchr(orig, (int) ' ') + 2;#ifdef EMPTYAWAY		xfree(status.awaymsg);		status.awaymsg = xstrdup(t);		/* Away / custom message. */		status.awaystate |= AWAY | CUSTOM;#else /* EMPTYAWAY */		FREE(status.awaymsg);		if (*t != '\0') {			status.awaymsg = xstrdup(t);			/* Away / custom message. */			status.awaystate |= AWAY | CUSTOM;		} else {			/* Not away / no custom message. */			status.awaystate &= ~AWAY & ~CUSTOM;		}#endif /* EMPTYAWAY */	} 	return 1;} /* static int cmd_away(char *par0, char *par1) */   static voidpass_cmd(connection_type *client, char *cmd, char *par0, char *par1,		const char *bufbu){	const char *buf;	/*	 * Use buffer from client unless bufbu is set. Having bufbu set	 * means client is invalid and should not be used.	 */	if (bufbu != NULL) {		buf = bufbu;	} else {		buf = client->buffer;	} 	if (i_server.connected == 2) {		int msg; 		/* Pass the message to server. */		irc_write(&c_server, "%s", buf); 		msg = ((xstrcmp(cmd, "PRIVMSG") == 0) ||			(xstrcmp(cmd, "NOTICE") == 0)) ? 1 : 0;		/* Echo the meesage to other clients. */		if (msg == 1) {			char tmp[IRC_MSGLEN + 1];			const char *cl_out = NULL;			llist_node *iter; 			if (cfg.privmsg_fmt != NULL &&					channel_is_name(par0) == 0) {				int i;				/* if the message is too long to fit the buffer				 * then it's a shame. sorry. */				i = snprintf(tmp, IRC_MSGLEN,						cfg.privmsg_fmt,						status.nickname);				tmp[i] = tmp[IRC_MSGLEN] = '\0';				strncat(tmp, par1 + 1, 510 - i);				cl_out = tmp;			} 			for (iter = c_clients.clients->head; iter != NULL;					iter = iter->next) {				connection_type *conn =					(connection_type *) iter->data;				if (iter->data == client) {					continue;				} 				if (cl_out == NULL) {					irc_write(conn, ":%s!%s %s",							status.nickname,							status.idhostname,							buf);				} else {					irc_write(conn, ":%s!%s %s %s %s",							par0,							"dummy",							cmd,							par0,							cl_out);				}			}		} #ifdef QUICKLOG		/* Also put it in quicklog. If necessary, or course. */		if (cfg.flushqlog == 0 && par0 != NULL && msg == 1) {			qlog_write(0, ":%s!%s@%s %s",					status.nickname,					i_client.username,					i_client.hostname,					buf);		}#endif /* QUICKLOG */	} else {		irc_notice(client, status.nickname, CLNT_NOTCONNECT);	}} /* static void pass_cmd(connection_type *client, char *cmd,		char *par0, char *par1, const char *bufbu) */   intclient_read(connection_type *client){	int c_status;	char *command, *param1, *param2;	char *orig;	int pass; 	c_status = irc_read(client); 	if (c_status <= 0) {		/* Something went unexpected. */		return c_status;	} 	/* Ok, got something. */	if (client->buffer[0] == '\0') {		/* Darn, got nothing after all. */		return 0;	} 	work = xstrdup(client->buffer);	orig = NULL; 	command = strtok(work, " "); 	if (command == NULL) {		xfree(work);		work = NULL;		return 0;	} 	param1 = strtok(NULL, " ");	param2 = strtok(NULL, "\0");	if (param1 != NULL && *param1 == ':') {		param1++;	} 	upcase(command); 	/* Commands from client when not connected to IRC-server. */	if (i_server.connected != 2) {		/* Willing to leave channels. */		if (xstrcmp(command, "PART") == 0) {			cmd_part(param1, param2);		}		/* Willing to join or leave channels. */		else if (xstrcmp(command, "JOIN") == 0) {			cmd_join(param1, param2);		}	} 	pass = 1; /* pass by default */ 	if (xstrcmp(command, "PRIVMSG") == 0) {		if (param2 == NULL) {#ifdef ENDUSERDEBUG			enduserdebug("client_read(): PRIVMSG, param2 = NULL");#endif /* ifdef ENDUSERDEBUG */		}#ifdef DCCBOUNCE		else if (param2[0] == ':' && param2[1] == '\1') {			pass = cmd_privmsg_ctcp(param1, param2);		}#endif /* ifdef DCCBOUNCE */#ifdef NEED_LOGGING		if (param2 != NULL && pass == 1) {			pass = cmd_privmsg(param1, param2);		}#endif /* ifdef NEED_LOGGING */	} 

Lines 1–500 of 590.