Exemplo n.º 1
0
static xt_status handle_channel(struct xt_node *node, gpointer data)
{
	struct xml_parsedata *xd = data;
	irc_channel_t *ic;
	char *name, *type;

	name = xt_find_attr(node, "name");
	type = xt_find_attr(node, "type");

	if (!name || !type) {
		return XT_ABORT;
	}

	/* The channel may exist already, for example if it's &bitlbee.
	   Also, it's possible that the user just reconnected and the
	   IRC client already rejoined all channels it was in. They
	   should still get the right settings. */
	if ((ic = irc_channel_by_name(xd->irc, name)) ||
	    (ic = irc_channel_new(xd->irc, name))) {
		set_setstr(&ic->set, "type", type);
	}

	handle_settings(node, &ic->set);

	return XT_HANDLED;
}
Exemplo n.º 2
0
irc_channel_t *irc_channel_new(irc_t *irc, const char *name)
{
	irc_channel_t *ic;
	set_t *s;

	if (!irc_channel_name_ok(name) || irc_channel_by_name(irc, name)) {
		return NULL;
	}

	ic = g_new0(irc_channel_t, 1);
	ic->irc = irc;
	ic->name = g_strdup(name);
	strcpy(ic->mode, CMODE);

	irc_channel_add_user(ic, irc->root);

	irc->channels = g_slist_append(irc->channels, ic);

	set_add(&ic->set, "auto_join", "false", set_eval_bool, ic);

	s = set_add(&ic->set, "type", "control", set_eval_channel_type, ic);
	s->flags |= SET_NOSAVE;    /* Layer violation (XML format detail) */

	if (name[0] == '&') {
		set_setstr(&ic->set, "type", "control");
	} else { /* if( name[0] == '#' ) */
		set_setstr(&ic->set, "type", "chat");
	}

	return ic;
}
Exemplo n.º 3
0
static void irc_cmd_mode( irc_t *irc, char **cmd )
{
	if( irc_channel_name_ok( cmd[1] ) )
	{
		irc_channel_t *ic;
		
		if( ( ic = irc_channel_by_name( irc, cmd[1] ) ) == NULL )
			irc_send_num( irc, 403, "%s :No such channel", cmd[1] );
		else if( cmd[2] )
		{
			if( *cmd[2] == '+' || *cmd[2] == '-' )
				irc_send_num( irc, 477, "%s :Can't change channel modes", cmd[1] );
			else if( *cmd[2] == 'b' )
				irc_send_num( irc, 368, "%s :No bans possible", cmd[1] );
		}
		else
			irc_send_num( irc, 324, "%s +%s", cmd[1], ic->mode );
	}
	else
	{
		if( nick_cmp( cmd[1], irc->user->nick ) == 0 )
		{
			if( cmd[2] )
				irc_umode_set( irc, cmd[2], 0 );
			else
				irc_send_num( irc, 221, "+%s", irc->umode );
		}
		else
			irc_send_num( irc, 502, ":Don't touch their modes" );
	}
}
Exemplo n.º 4
0
static void irc_cmd_privmsg( irc_t *irc, char **cmd )
{
	irc_channel_t *ic;
	irc_user_t *iu;
	
	if( !cmd[2] ) 
	{
		irc_send_num( irc, 412, ":No text to send" );
		return;
	}
	
	/* Don't treat CTCP actions as real CTCPs, just convert them right now. */
	if( g_strncasecmp( cmd[2], "\001ACTION", 7 ) == 0 )
	{
		cmd[2] += 4;
		memcpy( cmd[2], "/me", 3 );
		if( cmd[2][strlen(cmd[2])-1] == '\001' )
			cmd[2][strlen(cmd[2])-1] = '\0';
	}
	
	if( irc_channel_name_ok( cmd[1] ) &&
	    ( ic = irc_channel_by_name( irc, cmd[1] ) ) )
	{
		if( cmd[2][0] == '\001' )
		{
			/* CTCPs to channels? Nah. Maybe later. */
		}
		else if( ic->f->privmsg )
			ic->f->privmsg( ic, cmd[2] );
	}
	else if( ( iu = irc_user_by_name( irc, cmd[1] ) ) )
	{
		if( cmd[2][0] == '\001' )
		{
			char **ctcp;
			
			if( iu->f->ctcp == NULL )
				return;
			if( cmd[2][strlen(cmd[2])-1] == '\001' )
				cmd[2][strlen(cmd[2])-1] = '\0';
			
			ctcp = split_command_parts( cmd[2] + 1 );
			iu->f->ctcp( iu, ctcp );
		}
		else if( iu->f->privmsg )
		{
			iu->last_channel = NULL;
			iu->f->privmsg( iu, cmd[2] );
		}
	}
	else
	{
		irc_send_num( irc, 401, "%s :No such nick/channel", cmd[1] );
	}
}
Exemplo n.º 5
0
static gboolean irc_channel_free_callback(gpointer data, gint fd, b_input_condition cond)
{
	struct irc_channel_free_data *d = data;

	if (g_slist_find(irc_connection_list, d->irc) &&
	    irc_channel_by_name(d->irc, d->name) == d->ic &&
	    !(d->ic->flags & IRC_CHANNEL_JOINED)) {
		irc_channel_free(d->ic);
	}

	g_free(d->name);
	g_free(d);
	return FALSE;
}
Exemplo n.º 6
0
static void irc_cmd_names( irc_t *irc, char **cmd )
{
	irc_channel_t *ic;
	
	if( cmd[1] && ( ic = irc_channel_by_name( irc, cmd[1] ) ) )
		irc_send_names( ic );
	/* With no args, we should show /names of all chans. Make the code
	   below work well if necessary.
	else
	{
		GSList *l;
		
		for( l = irc->channels; l; l = l->next )
			irc_send_names( l->data );
	}
	*/
}
Exemplo n.º 7
0
static void irc_cmd_topic( irc_t *irc, char **cmd )
{
	irc_channel_t *ic = irc_channel_by_name( irc, cmd[1] );
	const char *new = cmd[2];
	
	if( ic == NULL )
	{
		irc_send_num( irc, 403, "%s :No such channel", cmd[1] );
	}
	else if( new )
	{
		if( ic->f->topic == NULL )
			irc_send_num( irc, 482, "%s :Can't change this channel's topic", ic->name );
		else if( ic->f->topic( ic, new ) )
			irc_send_topic( ic, TRUE );
	}
	else
	{
Exemplo n.º 8
0
static void irc_cmd_part( irc_t *irc, char **cmd )
{
	irc_channel_t *ic;
	
	if( ( ic = irc_channel_by_name( irc, cmd[1] ) ) == NULL )
	{
		irc_send_num( irc, 403, "%s :No such channel", cmd[1] );
	}
	else if( irc_channel_del_user( ic, irc->user, IRC_CDU_PART, cmd[2] ) )
	{
		if( ic->f->part )
			ic->f->part( ic, NULL );
	}
	else
	{
		irc_send_num( irc, 442, "%s :You're not on that channel", cmd[1] );
	}
}
Exemplo n.º 9
0
static void irc_cmd_who( irc_t *irc, char **cmd )
{
	char *channel = cmd[1];
	irc_channel_t *ic;
	irc_user_t *iu;
	
	if( !channel || *channel == '0' || *channel == '*' || !*channel )
		irc_send_who( irc, irc->users, "**" );
	else if( ( ic = irc_channel_by_name( irc, channel ) ) )
		irc_send_who( irc, ic->users, channel );
	else if( ( iu = irc_user_by_name( irc, channel ) ) )
	{
		/* Tiny hack! */
		GSList *l = g_slist_append( NULL, iu );
		irc_send_who( irc, l, channel );
		g_slist_free( l );
	}
	else
		irc_send_num( irc, 403, "%s :No such channel", channel );
}
Exemplo n.º 10
0
static void irc_cmd_invite( irc_t *irc, char **cmd )
{
	irc_channel_t *ic;
	irc_user_t *iu;
	
	if( ( iu = irc_user_by_name( irc, cmd[1] ) ) == NULL )
	{
		irc_send_num( irc, 401, "%s :No such nick", cmd[1] );
		return;
	}
	else if( ( ic = irc_channel_by_name( irc, cmd[2] ) ) == NULL )
	{
		irc_send_num( irc, 403, "%s :No such channel", cmd[2] );
		return;
	}
	
	if( !ic->f->invite )
		irc_send_num( irc, 482, "%s :Can't invite people here", cmd[2] );
	else if( ic->f->invite( ic, iu ) )
		irc_send_num( irc, 341, "%s %s", iu->nick, ic->name );
}
Exemplo n.º 11
0
irc_channel_t *irc_channel_get(irc_t *irc, char *id)
{
	irc_channel_t *ic, *ret = NULL;
	GSList *l;
	int nr;

	if (sscanf(id, "%d", &nr) == 1 && nr < 1000) {
		for (l = irc->channels; l; l = l->next) {
			ic = l->data;
			if ((nr--) == 0) {
				return ic;
			}
		}

		return NULL;
	}

	/* Exact match first: Partial match only sucks if there's a channel
	   #aa and #aabb */
	if ((ret = irc_channel_by_name(irc, id))) {
		return ret;
	}

	for (l = irc->channels; l; l = l->next) {
		ic = l->data;

		if (strstr(ic->name, id)) {
			/* Make sure it's a unique match. */
			if (!ret) {
				ret = ic;
			} else {
				return NULL;
			}
		}
	}

	return ret;
}
Exemplo n.º 12
0
static void xml_start_element( GMarkupParseContext *ctx, const gchar *element_name, const gchar **attr_names, const gchar **attr_values, gpointer data, GError **error )
{
	struct xml_parsedata *xd = data;
	irc_t *irc = xd->irc;
	
	if( xd->unknown_tag > 0 )
	{
		xd->unknown_tag ++;
	}
	else if( g_strcasecmp( element_name, "user" ) == 0 )
	{
		char *nick = xml_attr( attr_names, attr_values, "nick" );
		char *pass = xml_attr( attr_names, attr_values, "password" );
		int st;
		
		if( !nick || !pass )
		{
			g_set_error( error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT,
			             "Missing attributes for %s element", element_name );
		}
		else if( ( st = md5_verify_password( xd->given_pass, pass ) ) == -1 )
		{
			xd->pass_st = XML_PASS_WRONG;
			g_set_error( error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT,
			             "Error while decoding password attribute" );
		}
		else if( st == 0 )
		{
			if( xd->pass_st != XML_PASS_CHECK_ONLY )
				xd->pass_st = XML_PASS_OK;
		}
		else
		{
			xd->pass_st = XML_PASS_WRONG;
			g_set_error( error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT,
			             "Password mismatch" );
		}
	}
	else if( xd->pass_st < XML_PASS_OK )
	{
		/* Let's not parse anything else if we only have to check
		   the password. */
	}
	else if( g_strcasecmp( element_name, "account" ) == 0 )
	{
		char *protocol, *handle, *server, *password = NULL, *autoconnect, *tag;
		char *pass_b64 = NULL;
		unsigned char *pass_cr = NULL;
		int pass_len;
		struct prpl *prpl = NULL;
		
		handle = xml_attr( attr_names, attr_values, "handle" );
		pass_b64 = xml_attr( attr_names, attr_values, "password" );
		server = xml_attr( attr_names, attr_values, "server" );
		autoconnect = xml_attr( attr_names, attr_values, "autoconnect" );
		tag = xml_attr( attr_names, attr_values, "tag" );
		
		protocol = xml_attr( attr_names, attr_values, "protocol" );
		if( protocol )
			prpl = find_protocol( protocol );
		
		if( !handle || !pass_b64 || !protocol )
			g_set_error( error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT,
			             "Missing attributes for %s element", element_name );
		else if( !prpl )
			g_set_error( error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT,
			             "Unknown protocol: %s", protocol );
		else if( ( pass_len = base64_decode( pass_b64, (unsigned char**) &pass_cr ) ) &&
		         arc_decode( pass_cr, pass_len, &password, xd->given_pass ) >= 0 )
		{
			xd->current_account = account_add( irc->b, prpl, handle, password );
			if( server )
				set_setstr( &xd->current_account->set, "server", server );
			if( autoconnect )
				set_setstr( &xd->current_account->set, "auto_connect", autoconnect );
			if( tag )
				set_setstr( &xd->current_account->set, "tag", tag );
		}
		else
		{
			/* Actually the _decode functions don't even return error codes,
			   but maybe they will later... */
			g_set_error( error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT,
			             "Error while decrypting account password" );
		}
		
		g_free( pass_cr );
		g_free( password );
	}
	else if( g_strcasecmp( element_name, "setting" ) == 0 )
	{
		char *setting;
		
		if( xd->current_setting )
		{
			g_free( xd->current_setting );
			xd->current_setting = NULL;
		}
		
		if( ( setting = xml_attr( attr_names, attr_values, "name" ) ) )
		{
			if( xd->current_channel != NULL )
				xd->current_set_head = &xd->current_channel->set;
			else if( xd->current_account != NULL )
				xd->current_set_head = &xd->current_account->set;
			else
				xd->current_set_head = &xd->irc->b->set;
			
			xd->current_setting = g_strdup( setting );
		}
		else
			g_set_error( error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT,
			             "Missing attributes for %s element", element_name );
	}
	else if( g_strcasecmp( element_name, "buddy" ) == 0 )
	{
		char *handle, *nick;
		
		handle = xml_attr( attr_names, attr_values, "handle" );
		nick = xml_attr( attr_names, attr_values, "nick" );
		
		if( xd->current_account && handle && nick )
		{
			nick_set_raw( xd->current_account, handle, nick );
		}
		else
		{
			g_set_error( error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT,
			             "Missing attributes for %s element", element_name );
		}
	}
	else if( g_strcasecmp( element_name, "channel" ) == 0 )
	{
		char *name, *type;
		
		name = xml_attr( attr_names, attr_values, "name" );
		type = xml_attr( attr_names, attr_values, "type" );
		
		if( !name || !type )
		{
			g_set_error( error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT,
			             "Missing attributes for %s element", element_name );
			return;
		}
		
		/* The channel may exist already, for example if it's &bitlbee.
		   Also, it's possible that the user just reconnected and the
		   IRC client already rejoined all channels it was in. They
		   should still get the right settings. */
		if( ( xd->current_channel = irc_channel_by_name( irc, name ) ) ||
		    ( xd->current_channel = irc_channel_new( irc, name ) ) )
			set_setstr(&xd->current_channel->set, "type", type );
	}
	/* Backward compatibility: Keep this around for a while for people
	   switching from BitlBee 1.2.4+. */
	else if( g_strcasecmp( element_name, "chat" ) == 0 )
	{
		char *handle, *channel;
		
		handle = xml_attr( attr_names, attr_values, "handle" );
		channel = xml_attr( attr_names, attr_values, "channel" );
		
		if( xd->current_account && handle && channel )
		{
			irc_channel_t *ic;
			
			if( ( ic = irc_channel_new( irc, channel ) ) &&
			    set_setstr( &ic->set, "type", "chat" ) &&
			    set_setstr( &ic->set, "chat_type", "room" ) &&
			    set_setstr( &ic->set, "account", xd->current_account->tag ) &&
			    set_setstr( &ic->set, "room", handle ) )
			{
				/* Try to pick up some settings where possible. */
				xd->current_channel = ic;
			}
			else if( ic )
				irc_channel_free( ic );
		}
		else
		{
			g_set_error( error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT,
			             "Missing attributes for %s element", element_name );
		}
	}
	else
	{
		xd->unknown_tag ++;
		irc_rootmsg( irc, "Warning: Unknown XML tag found in configuration file (%s). "
		                  "This may happen when downgrading BitlBee versions. "
		                  "This tag will be skipped and the information will be lost "
		                  "once you save your settings.", element_name );
		/*
		g_set_error( error, G_MARKUP_ERROR, G_MARKUP_ERROR_UNKNOWN_ELEMENT,
		             "Unkown element: %s", element_name );
		*/
	}
}
Exemplo n.º 13
0
static void irc_cmd_join( irc_t *irc, char **cmd )
{
	char *comma, *s = cmd[1];
	
	while( s )
	{
		irc_channel_t *ic;
		
		if( ( comma = strchr( s, ',' ) ) )
			*comma = '\0';
		
		if( ( ic = irc_channel_by_name( irc, s ) ) == NULL &&
		    ( ic = irc_channel_new( irc, s ) ) )
		{
			if( strcmp( set_getstr( &ic->set, "type" ), "control" ) != 0 )
			{
				/* Autoconfiguration is for control channels only ATM. */
			}
			else if( bee_group_by_name( ic->irc->b, ic->name + 1, FALSE ) )
			{
				set_setstr( &ic->set, "group", ic->name + 1 );
				set_setstr( &ic->set, "fill_by", "group" );
			}
			else if( set_setstr( &ic->set, "protocol", ic->name + 1 ) )
			{
				set_setstr( &ic->set, "fill_by", "protocol" );
			}
			else if( set_setstr( &ic->set, "account", ic->name + 1 ) )
			{
				set_setstr( &ic->set, "fill_by", "account" );
			}
			else
			{
				/* The set commands above will run this already,
				   but if we didn't hit any, we have to fill the
				   channel with the default population. */
				bee_irc_channel_update( ic->irc, ic, NULL );
			}
		}
		else if( ic == NULL )
		{
			irc_send_num( irc, 479, "%s :Invalid channel name", s );
			goto next;
		}
		
		if( ic->flags & IRC_CHANNEL_JOINED )
			/* Dude, you're already there...
			   RFC doesn't have any reply for that though? */
			goto next;
		
		if( ic->f->join && !ic->f->join( ic ) )
			/* The story is: FALSE either means the handler
			   showed an error message, or is doing some work
			   before the join should be confirmed. (In the
			   latter case, the caller should take care of that
			   confirmation.) TRUE means all's good, let the
			   user join the channel right away. */
			goto next;
		
		irc_channel_add_user( ic, irc->user );
		
next:
		if( comma )
		{
			s = comma + 1;
			*comma = ',';
		}
		else
			break;
	}
}