Пример #1
0
static void
irc_quit (server *serv, char *reason)
{
	if (reason[0])
		tcp_sendf (serv, "QUIT :%s\r\n", reason);
	else
		tcp_send_len (serv, "QUIT\r\n", 6);
}
Пример #2
0
void
inbound_cap_ack (server *serv, char *nick, char *extensions,
					  const message_tags_data *tags_data)
{
	char *pass; /* buffer for SASL password */

	EMIT_SIGNAL_TIMESTAMP (XP_TE_CAPACK, serv->server_session, nick, extensions,
								  NULL, NULL, 0, tags_data->timestamp);

	if (strstr (extensions, "identify-msg") != NULL)
	{
		serv->have_idmsg = TRUE;
	}

	if (strstr (extensions, "multi-prefix") != NULL)
	{
		serv->have_namesx = TRUE;
	}

	if (strstr (extensions, "away-notify") != NULL)
	{
		serv->have_awaynotify = TRUE;
	}

	if (strstr (extensions, "account-notify") != NULL)
	{
		serv->have_accnotify = TRUE;
	}
					
	if (strstr (extensions, "extended-join") != NULL)
	{
		serv->have_extjoin = TRUE;
	}

	if (strstr (extensions, "server-time") != NULL)
	{
		serv->have_server_time = TRUE;
	}

	if (strstr (extensions, "sasl") != NULL)
	{
		char *user;

		serv->have_sasl = TRUE;

		user = (((ircnet *)serv->network)->user) 
			? (((ircnet *)serv->network)->user) : prefs.hex_irc_user_name;

		EMIT_SIGNAL_TIMESTAMP (XP_TE_SASLAUTH, serv->server_session, user, NULL,
									  NULL,	NULL,	0,	tags_data->timestamp);
		tcp_send_len (serv, "AUTHENTICATE PLAIN\r\n", 20);

		pass = encode_sasl_pass (user, serv->password);
		tcp_sendf (serv, "AUTHENTICATE %s\r\n", pass);
		free (pass);
	}
}
Пример #3
0
void
inbound_cap_nak (server *serv, const message_tags_data *tags_data)
{
	if (!serv->waiting_on_cap && !serv->sent_capend)
	{
		serv->sent_capend = TRUE;
		tcp_send_len (serv, "CAP END\r\n", 9);
	}
}
Пример #4
0
static int
irc_raw (server *serv, char *raw)
{
	int len;
	char tbuf[4096];
	if (*raw)
	{
		len = strlen (raw);
		if (len < sizeof (tbuf) - 3)
		{
			len = snprintf (tbuf, sizeof (tbuf), "%s\r\n", raw);
			tcp_send_len (serv, tbuf, len);
		} else
		{
			tcp_send_len (serv, raw, len);
			tcp_send_len (serv, "\r\n", 2);
		}
		return TRUE;
	}
	return FALSE;
}
Пример #5
0
static void
irc_list_channels (server *serv, char *arg, int min_users)
{
	if (arg[0])
	{
		tcp_sendf (serv, "LIST %s\r\n", arg);
		return;
	}

	if (serv->use_listargs)
		tcp_sendf (serv, "LIST >%d,<10000\r\n", min_users - 1);
	else
		tcp_send_len (serv, "LIST\r\n", 6);
}
Пример #6
0
bool
server::p_raw(const boost::string_ref &raw)
{
	char tbuf[4096];
	if (!raw.empty())
	{
		if (raw.size() < sizeof (tbuf) - 3)
		{
			auto len = snprintf(tbuf, sizeof(tbuf), "%s\r\n", raw.data());
			if (len < 0)
			{
				PrintText(current_sess, _("Unable to send message to server, and error has occurred"));
				return false;
			}
			tcp_send_len(*this, boost::string_ref{ tbuf, static_cast<std::size_t>(len)});
		} else
		{
			tcp_send_len (*this, raw);
			tcp_send_len(*this, boost::string_ref{ "\r\n", 2 });
		}
		return true;
	}
	return false;
}
Пример #7
0
static void
process_named_msg (session *sess, char *type, char *word[], char *word_eol[])
{
	server *serv = sess->server;
	char ip[128], nick[NICKLEN];
	char *text, *ex;
	int len = strlen (type);

	/* fill in the "ip" and "nick" buffers */
	ex = strchr (word[1], '!');
	if (!ex)							  /* no '!', must be a server message */
	{
		safe_strcpy (ip, word[1], sizeof (ip));
		safe_strcpy (nick, word[1], sizeof (nick));
	} else
	{
		safe_strcpy (ip, ex + 1, sizeof (ip));
		ex[0] = 0;
		safe_strcpy (nick, word[1], sizeof (nick));
		ex[0] = '!';
	}

	if (len == 4)
	{
		guint32 t;

		t = WORDL((guint8)type[0], (guint8)type[1], (guint8)type[2], (guint8)type[3]); 	
		/* this should compile to a bunch of: CMP.L, JE ... nice & fast */
		switch (t)
		{
		case WORDL('J','O','I','N'):
			{
				char *chan = word[3];

				if (*chan == ':')
					chan++;
				if (!serv->p_cmp (nick, serv->nick))
					inbound_ujoin (serv, chan, nick, ip);
				else
					inbound_join (serv, chan, nick, ip);
			}
			return;

		case WORDL('K','I','C','K'):
			{
				char *kicked = word[4];
				char *reason = word_eol[5];
				if (*kicked)
				{
					if (*reason == ':')
						reason++;
					if (!strcmp (kicked, serv->nick))
	 					inbound_ukick (serv, word[3], nick, reason);
					else
						inbound_kick (serv, word[3], kicked, nick, reason);
				}
			}
			return;

		case WORDL('K','I','L','L'):
			EMIT_SIGNAL (XP_TE_KILL, sess, nick, word_eol[5], NULL, NULL, 0);
			return;

		case WORDL('M','O','D','E'):
			handle_mode (serv, word, word_eol, nick, FALSE);	/* modes.c */
			return;

		case WORDL('N','I','C','K'):
			inbound_newnick (serv, nick, (word_eol[3][0] == ':')
									? word_eol[3] + 1 : word_eol[3], FALSE);
			return;

		case WORDL('P','A','R','T'):
			{
				char *chan = word[3];
				char *reason = word_eol[4];

				if (*chan == ':')
					chan++;
				if (*reason == ':')
					reason++;
				if (!strcmp (nick, serv->nick))
					inbound_upart (serv, chan, ip, reason);
				else
					inbound_part (serv, chan, nick, ip, reason);
			}
			return;

		case WORDL('P','O','N','G'):
			inbound_ping_reply (serv->server_session,
								 (word[4][0] == ':') ? word[4] + 1 : word[4], word[3]);
			return;

		case WORDL('Q','U','I','T'):
			inbound_quit (serv, nick, ip,
							  (word_eol[3][0] == ':') ? word_eol[3] + 1 : word_eol[3]);
			return;
		}

		goto garbage;
	}

	else if (len >= 5)
	{
		guint32 t;

		t = WORDL((guint8)type[0], (guint8)type[1], (guint8)type[2], (guint8)type[3]); 	
		/* this should compile to a bunch of: CMP.L, JE ... nice & fast */
		switch (t)
		{
		case WORDL('I','N','V','I'):
			if (ignore_check (word[1], IG_INVI))
				return;
			
			if (word[4][0] == ':')
				EMIT_SIGNAL (XP_TE_INVITED, sess, word[4] + 1, nick,
								 serv->servername, NULL, 0);
			else
				EMIT_SIGNAL (XP_TE_INVITED, sess, word[4], nick,
								 serv->servername, NULL, 0);
				
			return;

		case WORDL('N','O','T','I'):
			{
				int id = FALSE;	/* identified */

				text = word_eol[4];
				if (*text == ':')
					text++;

				if (serv->have_idmsg)
				{
					if (*text == '+')
					{
						id = TRUE;
						text++;
					} else if (*text == '-')
						text++;
				}

				if (!ignore_check (word[1], IG_NOTI))
					inbound_notice (serv, word[3], nick, text, ip, id);
			}
			return;

		case WORDL('P','R','I','V'):
			{
				char *to = word[3];
				int len;
				int id = FALSE;	/* identified */
				if (*to)
				{
					text = word_eol[4];
					if (*text == ':')
						text++;
					if (serv->have_idmsg)
					{
						if (*text == '+')
						{
							id = TRUE;
							text++;
						} else if (*text == '-')
							text++;
					}
					len = strlen (text);
					if (text[0] == 1 && text[len - 1] == 1)	/* ctcp */
					{
						text[len - 1] = 0;
						text++;
						if (strncasecmp (text, "ACTION", 6) != 0)
							flood_check (nick, ip, serv, sess, 0);
						if (strncasecmp (text, "DCC ", 4) == 0)
							/* redo this with handle_quotes TRUE */
							process_data_init (word[1], word_eol[1], word, word_eol, TRUE, FALSE);
						ctcp_handle (sess, to, nick, ip, text, word, word_eol, id);
					} else
					{
						if (is_channel (serv, to))
						{
							if (ignore_check (word[1], IG_CHAN))
								return;
							inbound_chanmsg (serv, NULL, to, nick, text, FALSE, id);
						} else
						{
							if (ignore_check (word[1], IG_PRIV))
								return;
							inbound_privmsg (serv, nick, ip, text, id);
						}
					}
				}
			}
			return;

		case WORDL('T','O','P','I'):
			inbound_topicnew (serv, nick, word[3],
									(word_eol[4][0] == ':') ? word_eol[4] + 1 : word_eol[4]);
			return;

		case WORDL('W','A','L','L'):
			text = word_eol[3];
			if (*text == ':')
				text++;
			EMIT_SIGNAL (XP_TE_WALLOPS, sess, nick, text, NULL, NULL, 0);
			return;
		}
	}

	else if (len == 3)
	{
		guint32 t;

		t = WORDL((guint8)type[0], (guint8)type[1], (guint8)type[2], (guint8)type[3]);
		switch (t)
		{
		case WORDL('C','A','P','\0'):
			if (strncasecmp(word[4], "ACK", 3) == 0)
			{
				if (strncasecmp(word[5][0]==':' ? word[5]+1 : word[5],
					"identify-msg", 12) == 0)
				{
					serv->have_idmsg = TRUE;
					tcp_send_len(serv, "CAP END\r\n", 9);
				}
			}
			else if (strncasecmp(word[4], "LS", 2) == 0)
			{
				if (strstr(word_eol[5], "identify-msg") != 0)
					tcp_send_len(serv, "CAP REQ :identify-msg\r\n", 23);
				else
					tcp_send_len(serv, "CAP END\r\n", 9);
			}
			else if (strncasecmp(word[4], "NAK",3) == 0)
			{
				tcp_send_len(serv, "CAP END\r\n", 9);
			}
			return;
		}
	}

garbage:
	/* unknown message */
	PrintTextf (sess, "GARBAGE: %s\n", word_eol[1]);
}
Пример #8
0
static void
irc_set_back (server *serv)
{
	tcp_send_len (serv, "AWAY\r\n", 6);
}
Пример #9
0
void
inbound_cap_ls (server *serv, char *nick, char *extensions_str,
					 const message_tags_data *tags_data)
{
	char buffer[256];	/* buffer for requesting capabilities and emitting the signal */
	guint32 want_cap; /* format the CAP REQ string based on previous capabilities being requested or not */
	guint32 want_sasl; /* CAP END shouldn't be sent when SASL is requested, it needs further responses */
	char **extensions;
	int i;

	EMIT_SIGNAL_TIMESTAMP (XP_TE_CAPLIST, serv->server_session, tags_data->timestamp, nick,
								  extensions_str);
	want_cap = 0;
	want_sasl = 0;

	extensions = g_strsplit (extensions_str, " ", 0);

	strcpy (buffer, "CAP REQ :");

	for (i=0; extensions[i]; i++)
	{
		const char *extension = extensions[i];

		if (!strcmp (extension, "identify-msg"))
		{
			strcat (buffer, "identify-msg ");
			want_cap = 1;
		}
		if (!strcmp (extension, "multi-prefix"))
		{
			strcat (buffer, "multi-prefix ");
			want_cap = 1;
		}
		if (!strcmp (extension, "away-notify"))
		{
			strcat (buffer, "away-notify ");
			want_cap = 1;
		}
		if (!strcmp (extension, "account-notify"))
		{
			strcat (buffer, "account-notify ");
			want_cap = 1;
		}
		if (!strcmp (extension, "extended-join"))
		{
			strcat (buffer, "extended-join ");
			want_cap = 1;
		}
		if (!strcmp (extension, "userhost-in-names"))
		{
			strcat (buffer, "userhost-in-names ");
			want_cap = 1;
		}

		/* bouncers can prefix a name space to the extension so we should use.
		 * znc <= 1.0 uses "znc.in/server-time" and newer use "znc.in/server-time-iso".
		 */
		if (!strcmp (extension, "znc.in/server-time-iso"))
		{
			strcat (buffer, "znc.in/server-time-iso ");
			want_cap = 1;
		}
		if (!strcmp (extension, "znc.in/server-time"))
		{
			strcat (buffer, "znc.in/server-time ");
			want_cap = 1;
		}
		if (prefs.hex_irc_cap_server_time
			 && !strcmp (extension, "server-time"))
		{
			strcat (buffer, "server-time ");
			want_cap = 1;
		}
		
		/* if the SASL password is set AND auth mode is set to SASL, request SASL auth */
		if (!strcmp (extension, "sasl")
			&& ((serv->loginmethod == LOGIN_SASL && strlen (serv->password) != 0)
			|| (serv->loginmethod == LOGIN_SASLEXTERNAL && serv->have_cert)))
		{
			strcat (buffer, "sasl ");
			want_cap = 1;
			want_sasl = 1;
		}
	}

	g_strfreev (extensions);

	if (want_cap)
	{
		/* buffer + 9 = emit buffer without "CAP REQ :" */
		EMIT_SIGNAL_TIMESTAMP (XP_TE_CAPREQ, serv->server_session, tags_data->timestamp, buffer + 9);
		tcp_sendf (serv, "%s\r\n", g_strchomp (buffer));
	}
	if (!want_sasl)
	{
		/* if we use SASL, CAP END is dealt via raw numerics */
		serv->sent_capend = TRUE;
		tcp_send_len (serv, "CAP END\r\n", 9);
	}
}
Пример #10
0
void
inbound_cap_ack (server *serv, char *nick, char *extensions,
					  const message_tags_data *tags_data)
{
	EMIT_SIGNAL_TIMESTAMP (XP_TE_CAPACK, serv->server_session, tags_data->timestamp, nick, extensions);

	if (strstr (extensions, "identify-msg") != NULL)
	{
		serv->have_idmsg = TRUE;
	}

	if (strstr (extensions, "multi-prefix") != NULL)
	{
		serv->have_namesx = TRUE;
	}

	if (strstr (extensions, "away-notify") != NULL)
	{
		serv->have_awaynotify = TRUE;
	}

	if (strstr (extensions, "account-notify") != NULL)
	{
		serv->have_accnotify = TRUE;
	}
					
	if (strstr (extensions, "extended-join") != NULL)
	{
		serv->have_extjoin = TRUE;
	}

	if (strstr (extensions, "userhost-in-names") != NULL)
	{
		serv->have_uhnames = TRUE;
	}

	if (strstr (extensions, "server-time") != NULL)
	{
		serv->have_server_time = TRUE;
	}

	if (strstr (extensions, "sasl") != NULL)
	{
		serv->have_sasl = TRUE;
		serv->sent_saslauth = FALSE;

#ifdef USE_OPENSSL
		if (serv->loginmethod == LOGIN_SASLEXTERNAL)
		{
			serv->sasl_mech = MECH_EXTERNAL;
			tcp_send_len (serv, "AUTHENTICATE EXTERNAL\r\n", 23);
		}
		else
		{
			/* default to most secure, it will fallback if not supported */
			serv->sasl_mech = MECH_AES;
			tcp_send_len (serv, "AUTHENTICATE DH-AES\r\n", 21);
		}
#else
		serv->sasl_mech = MECH_PLAIN;
		tcp_send_len (serv, "AUTHENTICATE PLAIN\r\n", 20);
#endif
	}
}
Пример #11
0
static void
process_numeric (session * sess, int n,
					  char *word[], char *word_eol[], char *text,
					  const message_tags_data *tags_data)
{
	server *serv = sess->server;
	/* show whois is the server tab */
	session *whois_sess = serv->server_session;
	
	/* unless this setting is on */
	if (prefs.hex_irc_whois_front)
		whois_sess = serv->front_session;

	switch (n)
	{
	case 1:
		inbound_login_start (sess, word[3], word[1], tags_data);
		/* if network is PTnet then you must get your IP address
			from "001" server message */
		if ((strncmp(word[7], "PTnet", 5) == 0) &&
			(strncmp(word[8], "IRC", 3) == 0) &&
			(strncmp(word[9], "Network", 7) == 0) &&
			(strrchr(word[10], '@') != NULL))
		{
			serv->use_who = FALSE;
			if (prefs.hex_dcc_ip_from_server)
				inbound_foundip (sess, strrchr(word[10], '@')+1, tags_data);
		}

		goto def;

	case 4:	/* check the ircd type */
		serv->use_listargs = FALSE;
		serv->modes_per_line = 3;		/* default to IRC RFC */
		if (strncmp (word[5], "bahamut", 7) == 0)				/* DALNet */
		{
			serv->use_listargs = TRUE;		/* use the /list args */
		} else if (strncmp (word[5], "u2.10.", 6) == 0)		/* Undernet */
		{
			serv->use_listargs = TRUE;		/* use the /list args */
			serv->modes_per_line = 6;		/* allow 6 modes per line */
		} else if (strncmp (word[5], "glx2", 4) == 0)
		{
			serv->use_listargs = TRUE;		/* use the /list args */
		}
		goto def;

	case 5:
		inbound_005 (serv, word, tags_data);
		goto def;

	case 263:	/*Server load is temporarily too heavy */
		if (fe_is_chanwindow (sess->server))
		{
			fe_chan_list_end (sess->server);
			fe_message (word_eol[4], FE_MSG_ERROR);
		}
		goto def;

	case 301:
		inbound_away (serv, word[4],
						  (word_eol[5][0] == ':') ? word_eol[5] + 1 : word_eol[5],
						  tags_data);
		break;

	case 302:
		if (serv->skip_next_userhost)
		{
			char *eq = strchr (word[4], '=');
			if (eq)
			{
				*eq = 0;
				if (!serv->p_cmp (word[4] + 1, serv->nick))
				{
					char *at = strrchr (eq + 1, '@');
					if (at)
						inbound_foundip (sess, at + 1, tags_data);
				}
			}

			serv->skip_next_userhost = FALSE;
			break;
		}
		else goto def;

	case 303:
		word[4]++;
		notify_markonline (serv, word, tags_data);
		break;

	case 305:
		inbound_uback (serv, tags_data);
		goto def;

	case 306:
		inbound_uaway (serv, tags_data);
		goto def;

	case 312:
		if (!serv->skip_next_whois)
			EMIT_SIGNAL_TIMESTAMP (XP_TE_WHOIS3, whois_sess, word[4], word_eol[5],
										  NULL, NULL, 0, tags_data->timestamp);
		else
			inbound_user_info (sess, NULL, NULL, NULL, word[5], word[4], NULL, NULL,
									 0xff, tags_data);
		break;

	case 311:	/* WHOIS 1st line */
		serv->inside_whois = 1;
		inbound_user_info_start (sess, word[4], tags_data);
		if (!serv->skip_next_whois)
			EMIT_SIGNAL_TIMESTAMP (XP_TE_WHOIS1, whois_sess, word[4], word[5],
										  word[6], word_eol[8] + 1, 0, tags_data->timestamp);
		else
			inbound_user_info (sess, NULL, word[5], word[6], NULL, word[4],
									 word_eol[8][0] == ':' ? word_eol[8] + 1 : word_eol[8],
									 NULL, 0xff, tags_data);
		break;

	case 314:	/* WHOWAS */
		inbound_user_info_start (sess, word[4], tags_data);
		EMIT_SIGNAL_TIMESTAMP (XP_TE_WHOIS1, whois_sess, word[4], word[5],
									  word[6], word_eol[8] + 1, 0, tags_data->timestamp);
		break;

	case 317:
		if (!serv->skip_next_whois)
		{
			time_t timestamp = (time_t) atol (word[6]);
			long idle = atol (word[5]);
			char *tim;
			char outbuf[64];

			snprintf (outbuf, sizeof (outbuf),
						"%02ld:%02ld:%02ld", idle / 3600, (idle / 60) % 60,
						idle % 60);
			if (timestamp == 0)
				EMIT_SIGNAL_TIMESTAMP (XP_TE_WHOIS4, whois_sess, word[4],
											  outbuf, NULL, NULL, 0, tags_data->timestamp);
			else
			{
				tim = ctime (&timestamp);
				tim[19] = 0; 	/* get rid of the \n */
				EMIT_SIGNAL_TIMESTAMP (XP_TE_WHOIS4T, whois_sess, word[4],
											  outbuf, tim, NULL, 0, tags_data->timestamp);
			}
		}
		break;

	case 318:	/* END OF WHOIS */
		if (!serv->skip_next_whois)
			EMIT_SIGNAL_TIMESTAMP (XP_TE_WHOIS6, whois_sess, word[4], NULL,
										  NULL, NULL, 0, tags_data->timestamp);
		serv->skip_next_whois = 0;
		serv->inside_whois = 0;
		break;

	case 313:
	case 319:
		if (!serv->skip_next_whois)
			EMIT_SIGNAL_TIMESTAMP (XP_TE_WHOIS2, whois_sess, word[4],
										  word_eol[5] + 1, NULL, NULL, 0,
										  tags_data->timestamp);
		break;

	case 307:	/* dalnet version */
	case 320:	/* :is an identified user */
		if (!serv->skip_next_whois)
			EMIT_SIGNAL_TIMESTAMP (XP_TE_WHOIS_ID, whois_sess, word[4],
										  word_eol[5] + 1, NULL, NULL, 0,
										  tags_data->timestamp);
		break;

	case 321:
		if (!fe_is_chanwindow (sess->server))
			EMIT_SIGNAL_TIMESTAMP (XP_TE_CHANLISTHEAD, serv->server_session, NULL,
										  NULL, NULL, NULL, 0, tags_data->timestamp);
		break;

	case 322:
		if (fe_is_chanwindow (sess->server))
		{
			fe_add_chan_list (sess->server, word[4], word[5], word_eol[6] + 1);
		} else
		{
			PrintTextTimeStampf (serv->server_session, tags_data->timestamp,
										"%-16s %-7d %s\017\n", word[4], atoi (word[5]),
										word_eol[6] + 1);
		}
		break;

	case 323:
		if (!fe_is_chanwindow (sess->server))
			EMIT_SIGNAL_TIMESTAMP (XP_TE_SERVTEXT, serv->server_session, text, 
										  word[1], word[2], NULL, 0, tags_data->timestamp);
		else
			fe_chan_list_end (sess->server);
		break;

	case 324:
		sess = find_channel (serv, word[4]);
		if (!sess)
			sess = serv->server_session;
		if (sess->ignore_mode)
			sess->ignore_mode = FALSE;
		else
			EMIT_SIGNAL_TIMESTAMP (XP_TE_CHANMODES, sess, word[4], word_eol[5],
										  NULL, NULL, 0, tags_data->timestamp);
		fe_update_mode_buttons (sess, 'c', '-');
		fe_update_mode_buttons (sess, 'r', '-');
		fe_update_mode_buttons (sess, 't', '-');
		fe_update_mode_buttons (sess, 'n', '-');
		fe_update_mode_buttons (sess, 'i', '-');
		fe_update_mode_buttons (sess, 'm', '-');
		fe_update_mode_buttons (sess, 'l', '-');
		fe_update_mode_buttons (sess, 'k', '-');
		handle_mode (serv, word, word_eol, "", TRUE, tags_data);
		break;

	case 328: /* channel url */
		sess = find_channel (serv, word[4]);
		if (sess)
		{
			EMIT_SIGNAL_TIMESTAMP (XP_TE_CHANURL, sess, word[4], word[5] + 1,
									NULL, NULL, 0, tags_data->timestamp); 
		}
		break;

	case 329:
		sess = find_channel (serv, word[4]);
		if (sess)
		{
			if (sess->ignore_date)
				sess->ignore_date = FALSE;
			else
				channel_date (sess, word[4], word[5], tags_data);
		}
		break;

	case 330:
		if (!serv->skip_next_whois)
			EMIT_SIGNAL_TIMESTAMP (XP_TE_WHOIS_AUTH, whois_sess, word[4],
										  word_eol[6] + 1, word[5], NULL, 0,
										  tags_data->timestamp);
		inbound_user_info (sess, NULL, NULL, NULL, NULL, word[4], NULL, word[5],
								 0xff, tags_data);
		break;

	case 332:
		inbound_topic (serv, word[4],
							(word_eol[5][0] == ':') ? word_eol[5] + 1 : word_eol[5],
							tags_data);
		break;

	case 333:
		inbound_topictime (serv, word[4], word[5], atol (word[6]), tags_data);
		break;

#if 0
	case 338:  /* Undernet Real user@host, Real IP */
		EMIT_SIGNAL_TIMESTAMP (XP_TE_WHOIS_REALHOST, sess, word[4], word[5], word[6], 
									  (word_eol[7][0]==':') ? word_eol[7]+1 : word_eol[7],
									  0, tags_data->timestamp);
		break;
#endif

	case 341:						  /* INVITE ACK */
		EMIT_SIGNAL_TIMESTAMP (XP_TE_UINVITE, sess, word[4], word[5],
									  serv->servername, NULL, 0, tags_data->timestamp);
		break;

	case 352:						  /* WHO */
		{
			unsigned int away = 0;
			session *who_sess = find_channel (serv, word[4]);

			if (*word[9] == 'G')
				away = 1;

			inbound_user_info (sess, word[4], word[5], word[6], word[7],
									 word[8], word_eol[11], NULL, away,
									 tags_data);

			/* try to show only user initiated whos */
			if (!who_sess || !who_sess->doing_who)
				EMIT_SIGNAL_TIMESTAMP (XP_TE_SERVTEXT, serv->server_session, text, word[1],
											  word[2], NULL, 0, tags_data->timestamp);
		}
		break;

	case 354:	/* undernet WHOX: used as a reply for irc_away_status */
		{
			unsigned int away = 0;
			session *who_sess;

			/* irc_away_status and irc_user_list sends out a "152" */
			if (!strcmp (word[4], "152"))
			{
				who_sess = find_channel (serv, word[5]);

				if (*word[10] == 'G')
					away = 1;

				/* :server 354 yournick 152 #channel ~ident host servname nick H account :realname */
				inbound_user_info (sess, word[5], word[6], word[7], word[8],
										 word[9], word_eol[12]+1, word[11], away,
										 tags_data);

				/* try to show only user initiated whos */
				if (!who_sess || !who_sess->doing_who)
					EMIT_SIGNAL_TIMESTAMP (XP_TE_SERVTEXT, serv->server_session, text,
												  word[1], word[2], NULL, 0,
												  tags_data->timestamp);
			} else
				goto def;
		}
		break;

	case 315:						  /* END OF WHO */
		{
			session *who_sess;
			who_sess = find_channel (serv, word[4]);
			if (who_sess)
			{
				if (!who_sess->doing_who)
					EMIT_SIGNAL_TIMESTAMP (XP_TE_SERVTEXT, serv->server_session, text,
												  word[1], word[2], NULL, 0,
												  tags_data->timestamp);
				who_sess->doing_who = FALSE;
			} else
			{
				if (!serv->doing_dns)
					EMIT_SIGNAL_TIMESTAMP (XP_TE_SERVTEXT, serv->server_session, text,
												  word[1], word[2], NULL, 0, tags_data->timestamp);
				serv->doing_dns = FALSE;
			}
		}
		break;

	case 346:	/* +I-list entry */
		if (!inbound_banlist (sess, atol (word[7]), word[4], word[5], word[6], 346,
									 tags_data))
			goto def;
		break;

	case 347:	/* end of invite list */
		if (!fe_ban_list_end (sess, 347))
			goto def;
		break;

	case 348:	/* +e-list entry */
		if (!inbound_banlist (sess, atol (word[7]), word[4], word[5], word[6], 348,
									 tags_data))
			goto def;
		break;

	case 349:	/* end of exemption list */
		sess = find_channel (serv, word[4]);
		if (!sess)
		{
			sess = serv->front_session;
			goto def;
		}
		if (!fe_ban_list_end (sess, 349))
			goto def;
		break;

	case 353:						  /* NAMES */
		inbound_nameslist (serv, word[5],
								 (word_eol[6][0] == ':') ? word_eol[6] + 1 : word_eol[6],
								 tags_data);
		break;

	case 366:
		if (!inbound_nameslist_end (serv, word[4], tags_data))
			goto def;
		break;

	case 367: /* banlist entry */
		if (!inbound_banlist (sess, atol (word[7]), word[4], word[5], word[6], 367,
									 tags_data))
			goto def;
		break;

	case 368:
		sess = find_channel (serv, word[4]);
		if (!sess)
		{
			sess = serv->front_session;
			goto def;
		}
		if (!fe_ban_list_end (sess, 368))
			goto def;
		break;

	case 369:	/* WHOWAS end */
	case 406:	/* WHOWAS error */
		EMIT_SIGNAL_TIMESTAMP (XP_TE_SERVTEXT, whois_sess, text, word[1], word[2],
									  NULL, 0, tags_data->timestamp);
		serv->inside_whois = 0;
		break;

	case 372:	/* motd text */
	case 375:	/* motd start */
		if (!prefs.hex_irc_skip_motd || serv->motd_skipped)
			EMIT_SIGNAL_TIMESTAMP (XP_TE_MOTD, serv->server_session, text, NULL,
										  NULL, NULL, 0, tags_data->timestamp);
		break;

	case 376:	/* end of motd */
	case 422:	/* motd file is missing */
		inbound_login_end (sess, text, tags_data);
		break;

	case 432:	/* erroneous nickname */
		if (serv->end_of_motd)
		{
			goto def;
		}
		inbound_next_nick (sess,  word[4], 1, tags_data);
		break;

	case 433:	/* nickname in use */
		if (serv->end_of_motd)
		{
			goto def;
		}
		inbound_next_nick (sess,  word[4], 0, tags_data);
		break;

	case 437:
		if (serv->end_of_motd || is_channel (serv, word[4]))
			goto def;
		inbound_next_nick (sess, word[4], 0, tags_data);
		break;

	case 471:
		EMIT_SIGNAL_TIMESTAMP (XP_TE_USERLIMIT, sess, word[4], NULL, NULL, NULL, 0,
									  tags_data->timestamp);
		break;

	case 473:
		EMIT_SIGNAL_TIMESTAMP (XP_TE_INVITE, sess, word[4], NULL, NULL, NULL, 0,
									  tags_data->timestamp);
		break;

	case 474:
		EMIT_SIGNAL_TIMESTAMP (XP_TE_BANNED, sess, word[4], NULL, NULL, NULL, 0,
									  tags_data->timestamp);
		break;

	case 475:
		EMIT_SIGNAL_TIMESTAMP (XP_TE_KEYWORD, sess, word[4], NULL, NULL, NULL, 0,
									  tags_data->timestamp);
		break;

	case 601:
		notify_set_offline (serv, word[4], FALSE, tags_data);
		break;

	case 605:
		notify_set_offline (serv, word[4], TRUE, tags_data);
		break;

	case 600:
	case 604:
		notify_set_online (serv, word[4], tags_data);
		break;

	case 728:	/* +q-list entry */
		/* NOTE:  FREENODE returns these results inconsistent with e.g. +b */
		/* Who else has imlemented MODE_QUIET, I wonder? */
		if (!inbound_banlist (sess, atol (word[8]), word[4], word[6], word[7], 728,
									 tags_data))
			goto def;
		break;

	case 729:	/* end of quiet list */
		if (!fe_ban_list_end (sess, 729))
			goto def;
		break;

	case 730: /* RPL_MONONLINE */
		notify_set_online_list (serv, word[4] + 1, tags_data);
		break;

	case 731: /* RPL_MONOFFLINE */
		notify_set_offline_list (serv, word[4] + 1, FALSE, tags_data);
		break;

	case 900:	/* successful SASL 'logged in as ' */
		EMIT_SIGNAL_TIMESTAMP (XP_TE_SERVTEXT, serv->server_session, 
									  word_eol[6]+1, word[1], word[2], NULL, 0,
									  tags_data->timestamp);
		break;
	case 903:	/* successful SASL auth */
	case 904:	/* failed SASL auth */
		if (inbound_sasl_error (serv))
			break; /* might retry */
	case 905:	/* failed SASL auth */
	case 906:	/* aborted */
	case 907:	/* attempting to re-auth after a successful auth */
		EMIT_SIGNAL_TIMESTAMP (XP_TE_SASLRESPONSE, serv->server_session, word[1],
									  word[2], word[3], ++word_eol[4], 0,
									  tags_data->timestamp);
		if (!serv->sent_capend)
		{
			serv->sent_capend = TRUE;
			tcp_send_len (serv, "CAP END\r\n", 9);
		}
		break;
	case 908:	/* Supported SASL Mechs */
		inbound_sasl_supportedmechs (serv, word[4]);
		break;

	default:

		if (serv->inside_whois && word[4][0])
		{
			/* some unknown WHOIS reply, ircd coders make them up weekly */
			if (!serv->skip_next_whois)
				EMIT_SIGNAL_TIMESTAMP (XP_TE_WHOIS_SPECIAL, whois_sess, word[4],
											  (word_eol[5][0] == ':') ? word_eol[5] + 1 : word_eol[5],
											  word[2], NULL, 0, tags_data->timestamp);
			return;
		}

	def:
		{
			session *sess;
		
			if (is_channel (serv, word[4]))
			{
				sess = find_channel (serv, word[4]);
				if (!sess)
					sess = serv->server_session;
			}
			else if ((sess=find_dialog (serv,word[4]))) /* user with an open dialog */
				;
			else
				sess=serv->server_session;
			
			EMIT_SIGNAL_TIMESTAMP (XP_TE_SERVTEXT, sess, text, word[1], word[2],
										  NULL, 0, tags_data->timestamp);
		}
	}
}
Пример #12
0
void
inbound_005 (server * serv, char *word[])
{
	int w;
	char *pre;

	w = 4;							  /* start at the 4th word */
	while (w < PDIWORDS && *word[w])
	{
		if (strncmp (word[w], "MODES=", 6) == 0)
		{
			serv->modes_per_line = atoi (word[w] + 6);
		} else if (strncmp (word[w], "CHANTYPES=", 10) == 0)
		{
			free (serv->chantypes);
			serv->chantypes = strdup (word[w] + 10);
		} else if (strncmp (word[w], "CHANMODES=", 10) == 0)
		{
			free (serv->chanmodes);
			serv->chanmodes = strdup (word[w] + 10);
		} else if (strncmp (word[w], "PREFIX=", 7) == 0)
		{
			pre = strchr (word[w] + 7, ')');
			if (pre)
			{
				pre[0] = 0;			  /* NULL out the ')' */
				free (serv->nick_prefixes);
				free (serv->nick_modes);
				serv->nick_prefixes = strdup (pre + 1);
				serv->nick_modes = strdup (word[w] + 8);
			} else
			{
				/* bad! some ircds don't give us the modes. */
				/* in this case, we use it only to strip /NAMES */
				serv->bad_prefix = TRUE;
				if (serv->bad_nick_prefixes)
					free (serv->bad_nick_prefixes);
				serv->bad_nick_prefixes = strdup (word[w] + 7);
			}
		} else if (strncmp (word[w], "WATCH=", 6) == 0)
		{
			serv->supports_watch = TRUE;
		} else if (strncmp (word[w], "MONITOR=", 8) == 0)
		{
			serv->supports_monitor = TRUE;
		} else if (strncmp (word[w], "NETWORK=", 8) == 0)
		{
/*			if (serv->networkname)
				free (serv->networkname);
			serv->networkname = strdup (word[w] + 8);*/

			if (serv->server_session->type == SESS_SERVER)
			{
				safe_strcpy (serv->server_session->channel, word[w] + 8, CHANLEN);
				fe_set_channel (serv->server_session);
			}

			/* use /NICKSERV */
			if (g_ascii_strcasecmp (word[w] + 8, "UniBG") == 0)
				serv->nickservtype = 3;
			else if (g_ascii_strcasecmp (word[w] + 8, "QuakeNet") == 0)
				serv->nickservtype = 4;

		} else if (strncmp (word[w], "CASEMAPPING=", 12) == 0)
		{
			if (strcmp (word[w] + 12, "ascii") == 0)	/* bahamut */
				serv->p_cmp = (void *)g_ascii_strcasecmp;
		} else if (strncmp (word[w], "CHARSET=", 8) == 0)
		{
			if (g_ascii_strcasecmp (word[w] + 8, "UTF-8") == 0)
			{
				server_set_encoding (serv, "UTF-8");
			}
		} else if (strcmp (word[w], "NAMESX") == 0)
		{
									/* 12345678901234567 */
			tcp_send_len (serv, "PROTOCTL NAMESX\r\n", 17);
		} else if (strcmp (word[w], "WHOX") == 0)
		{
			serv->have_whox = TRUE;
		} else if (strcmp (word[w], "EXCEPTS") == 0)
		{
#ifndef WIN32
			serv->have_except = TRUE;
#endif
		} else if (strcmp (word[w], "INVEX") == 0)
		{
			/* supports mode letter +I, default channel invite */
			serv->have_invite = TRUE;
		} else if (strncmp (word[w], "ELIST=", 6) == 0)
		{
			/* supports LIST >< min/max user counts? */
			if (strchr (word[w] + 6, 'U') || strchr (word[w] + 6, 'u'))
				serv->use_listargs = TRUE;
		}

		w++;
	}
}
Пример #13
0
void
inbound_cap_nak (server *serv, const message_tags_data *tags_data)
{
	tcp_send_len (serv, "CAP END\r\n", 9);
}
Пример #14
0
void
inbound_cap_ls (server *serv, char *nick, char *extensions_str,
					 const message_tags_data *tags_data)
{
	char buffer[500];	/* buffer for requesting capabilities and emitting the signal */
	gboolean want_cap = FALSE; /* format the CAP REQ string based on previous capabilities being requested or not */
	gboolean want_sasl = FALSE; /* CAP END shouldn't be sent when SASL is requested, it needs further responses */
	char **extensions;
	int i;

	if (g_str_has_prefix (extensions_str, "* "))
	{
		serv->waiting_on_cap = TRUE;
		extensions_str += 2;
		extensions_str += extensions_str[0] == ':' ? 1 : 0;
	}
	else
	{
		serv->waiting_on_cap = FALSE;
	}

	EMIT_SIGNAL_TIMESTAMP (XP_TE_CAPLIST, serv->server_session, nick,
								  extensions_str, NULL, NULL, 0, tags_data->timestamp);

	extensions = g_strsplit (extensions_str, " ", 0);

	strcpy (buffer, "CAP REQ :");

	for (i=0; extensions[i]; i++)
	{
		char *extension = extensions[i];
		char *value;
		gsize x;

		/* CAP 3.2 can provide values */
		if ((value = strchr (extension, '=')))
		{
			*value = '\0';
			value++;
		}

		/* if the SASL password is set AND auth mode is set to SASL, request SASL auth */
		if (!g_strcmp0 (extension, "sasl") &&
			((serv->loginmethod == LOGIN_SASL && strlen (serv->password) != 0)
				|| (serv->loginmethod == LOGIN_SASLEXTERNAL && serv->have_cert)))
		{
			if (value)
			{
				int sasl_mech = get_supported_mech (serv, value);
				if (sasl_mech == -1) /* No supported mech */
					continue;
				serv->sasl_mech = sasl_mech;
			}
			want_cap = TRUE;
			want_sasl = TRUE;
			g_strlcat (buffer, "sasl ", sizeof(buffer));
			continue;
		}

		for (x = 0; x < G_N_ELEMENTS(supported_caps); ++x)
		{
			if (!g_strcmp0 (extension, supported_caps[x]))
			{
				g_strlcat (buffer, extension, sizeof(buffer));
				g_strlcat (buffer, " ", sizeof(buffer));
				want_cap = TRUE;
			}
		}
	}

	g_strfreev (extensions);

	if (want_cap)
	{
		/* buffer + 9 = emit buffer without "CAP REQ :" */
		EMIT_SIGNAL_TIMESTAMP (XP_TE_CAPREQ, serv->server_session,
									  buffer + 9, NULL, NULL, NULL, 0,
									  tags_data->timestamp);
		tcp_sendf (serv, "%s\r\n", g_strchomp (buffer));
	}
	if (!want_sasl && !serv->waiting_on_cap)
	{
		/* if we use SASL, CAP END is dealt via raw numerics */
		serv->sent_capend = TRUE;
		tcp_send_len (serv, "CAP END\r\n", 9);
	}
}
Пример #15
0
static void
process_named_msg (session *sess, char *type, char *word[], char *word_eol[])
{
    server *serv = sess->server;
    char ip[128], nick[NICKLEN];
    char *text, *ex;
    int len = strlen (type);

    /* fill in the "ip" and "nick" buffers */
    ex = strchr (word[1], '!');
    if (!ex)							  /* no '!', must be a server message */
    {
        safe_strcpy (ip, word[1], sizeof (ip));
        safe_strcpy (nick, word[1], sizeof (nick));
    } else
    {
        safe_strcpy (ip, ex + 1, sizeof (ip));
        ex[0] = 0;
        safe_strcpy (nick, word[1], sizeof (nick));
        ex[0] = '!';
    }

    if (len == 4)
    {
        guint32 t;

        t = WORDL((guint8)type[0], (guint8)type[1], (guint8)type[2], (guint8)type[3]);
        /* this should compile to a bunch of: CMP.L, JE ... nice & fast */
        switch (t)
        {
        case WORDL('J','O','I','N'):
        {
            char *chan = word[3];

            if (*chan == ':')
                chan++;
            if (!serv->p_cmp (nick, serv->nick))
                inbound_ujoin (serv, chan, nick, ip);
            else
                inbound_join (serv, chan, nick, ip);
        }
        return;

        case WORDL('K','I','C','K'):
        {
            char *kicked = word[4];
            char *reason = word_eol[5];
            if (*kicked)
            {
                if (*reason == ':')
                    reason++;
                if (!strcmp (kicked, serv->nick))
                    inbound_ukick (serv, word[3], nick, reason);
                else
                    inbound_kick (serv, word[3], kicked, nick, reason);
            }
        }
        return;

        case WORDL('K','I','L','L'):
            EMIT_SIGNAL (XP_TE_KILL, sess, nick, word_eol[5], NULL, NULL, 0);
            return;

        case WORDL('M','O','D','E'):
            handle_mode (serv, word, word_eol, nick, FALSE);	/* modes.c */
            return;

        case WORDL('N','I','C','K'):
            inbound_newnick (serv, nick, (word_eol[3][0] == ':')
                             ? word_eol[3] + 1 : word_eol[3], FALSE);
            return;

        case WORDL('P','A','R','T'):
        {
            char *chan = word[3];
            char *reason = word_eol[4];

            if (*chan == ':')
                chan++;
            if (*reason == ':')
                reason++;
            if (!strcmp (nick, serv->nick))
                inbound_upart (serv, chan, ip, reason);
            else
                inbound_part (serv, chan, nick, ip, reason);
        }
        return;

        case WORDL('P','O','N','G'):
            inbound_ping_reply (serv->server_session,
                                (word[4][0] == ':') ? word[4] + 1 : word[4], word[3]);
            return;

        case WORDL('Q','U','I','T'):
            inbound_quit (serv, nick, ip,
                          (word_eol[3][0] == ':') ? word_eol[3] + 1 : word_eol[3]);
            return;
        }

        goto garbage;
    }

    else if (len >= 5)
    {
        guint32 t;

        t = WORDL((guint8)type[0], (guint8)type[1], (guint8)type[2], (guint8)type[3]);
        /* this should compile to a bunch of: CMP.L, JE ... nice & fast */
        switch (t)
        {
        case WORDL('I','N','V','I'):
            if (ignore_check (word[1], IG_INVI))
                return;

            if (word[4][0] == ':')
                EMIT_SIGNAL (XP_TE_INVITED, sess, word[4] + 1, nick,
                             serv->servername, NULL, 0);
            else
                EMIT_SIGNAL (XP_TE_INVITED, sess, word[4], nick,
                             serv->servername, NULL, 0);

            return;

        case WORDL('N','O','T','I'):
        {
            int id = FALSE;	/* identified */

            text = word_eol[4];
            if (*text == ':')
                text++;

            if (serv->have_idmsg)
            {
                if (*text == '+')
                {
                    id = TRUE;
                    text++;
                } else if (*text == '-')
                    text++;
            }

            if (!ignore_check (word[1], IG_NOTI))
                inbound_notice (serv, word[3], nick, text, ip, id);
        }
        return;

        case WORDL('P','R','I','V'):
        {
            char *to = word[3];
            int len;
            int id = FALSE;	/* identified */
            if (*to)
            {
                text = word_eol[4];
                if (*text == ':')
                    text++;
                if (serv->have_idmsg)
                {
                    if (*text == '+')
                    {
                        id = TRUE;
                        text++;
                    } else if (*text == '-')
                        text++;
                }
                len = strlen (text);
                if (text[0] == 1 && text[len - 1] == 1)	/* ctcp */
                {
                    text[len - 1] = 0;
                    text++;
                    if (g_ascii_strncasecmp (text, "ACTION", 6) != 0)
                        flood_check (nick, ip, serv, sess, 0);
                    if (g_ascii_strncasecmp (text, "DCC ", 4) == 0)
                        /* redo this with handle_quotes TRUE */
                        process_data_init (word[1], word_eol[1], word, word_eol, TRUE, FALSE);
                    ctcp_handle (sess, to, nick, ip, text, word, word_eol, id);
                } else
                {
                    if (is_channel (serv, to))
                    {
                        if (ignore_check (word[1], IG_CHAN))
                            return;
                        inbound_chanmsg (serv, NULL, to, nick, text, FALSE, id);
                    } else
                    {
                        if (ignore_check (word[1], IG_PRIV))
                            return;
                        inbound_privmsg (serv, nick, ip, text, id);
                    }
                }
            }
        }
        return;

        case WORDL('T','O','P','I'):
            inbound_topicnew (serv, nick, word[3],
                              (word_eol[4][0] == ':') ? word_eol[4] + 1 : word_eol[4]);
            return;

        case WORDL('W','A','L','L'):
            text = word_eol[3];
            if (*text == ':')
                text++;
            EMIT_SIGNAL (XP_TE_WALLOPS, sess, nick, text, NULL, NULL, 0);
            return;
        }
    }

    else if (len == 3)
    {
        guint32 t;
        guint32 want_cap;		/* format the CAP REQ string based on previous capabilities being requested or not */
        guint32 want_sasl;		/* CAP END shouldn't be sent when SASL is requested, it needs further responses */
        char *pass;				/* buffer for SASL password */
        char buffer[256];		/* buffer for requesting capabilities and emitting the signal */

        t = WORDL((guint8)type[0], (guint8)type[1], (guint8)type[2], (guint8)type[3]);
        switch (t)
        {
        case WORDL('C','A','P','\0'):
            if (strncasecmp (word[4], "ACK", 3) == 0)
            {
                EMIT_SIGNAL (XP_TE_CAPACK, sess->server->server_session, word[1], word[5][0]==':' ? ++word_eol[5] : word_eol[5], NULL, NULL, 0);

                if (strstr (word_eol[5], "identify-msg") != 0)
                {
                    serv->have_idmsg = TRUE;
                }

                if (strstr (word_eol[5], "multi-prefix") != 0)
                {
                    serv->have_namesx = TRUE;
                }

                if (strstr (word_eol[5], "sasl") != 0)
                {
                    serv->have_sasl = TRUE;
                    EMIT_SIGNAL (XP_TE_SASLAUTH, serv->server_session, sess->server->sasluser, NULL, NULL, NULL, 0);
                    tcp_send_len (serv, "AUTHENTICATE PLAIN\r\n", 20);

                    pass = encode_sasl_pass (sess->server->sasluser, sess->server->saslpassword);
                    tcp_sendf (sess->server, "AUTHENTICATE %s\r\n", pass);
                    free (pass);
                }
            }
            else if (strncasecmp (word[4], "LS", 2) == 0)
            {
                EMIT_SIGNAL (XP_TE_CAPLIST, serv->server_session, word[1], word[5][0]==':' ? ++word_eol[5] : word_eol[5], NULL, NULL, 0);
                want_cap = 0;
                want_sasl = 0;

                if (strstr (word_eol[5], "identify-msg") != 0)
                {
                    strcpy (buffer, "CAP REQ :identify-msg");
                    want_cap = 1;
                }
                if (strstr (word_eol[5], "multi-prefix") != 0)
                {
                    want_cap ? strcat (buffer, " multi-prefix") : strcpy (buffer, "CAP REQ :multi-prefix");
                    want_cap = 1;
                }
                /* if the SASL password is set, request SASL auth */
                if (strstr (word_eol[5], "sasl") != 0 && strlen (sess->server->saslpassword) != 0)
                {
                    want_cap ? strcat (buffer, " sasl") : strcpy (buffer, "CAP REQ :sasl");
                    want_sasl = 1;
                }

                if (want_cap)
                {
                    /* buffer + 9 = emit buffer without "CAP REQ :" */
                    EMIT_SIGNAL (XP_TE_CAPREQ, sess->server->server_session, buffer + 9, NULL, NULL, NULL, 0);
                    tcp_sendf (serv, "%s\r\n", buffer);
                }
                if (!want_sasl)
                {
                    /* if we use SASL, CAP END is dealt via raw numerics */
                    tcp_send_len (serv, "CAP END\r\n", 9);
                }
            }
            else if (strncasecmp (word[4], "NAK", 3) == 0)
            {
                tcp_send_len (serv, "CAP END\r\n", 9);
            }

            return;
        }
    }

garbage:
    /* unknown message */
    PrintTextf (sess, "GARBAGE: %s\n", word_eol[1]);
}
Пример #16
0
static void
process_numeric (session * sess, int n,
                 char *word[], char *word_eol[], char *text)
{
    server *serv = sess->server;
    /* show whois is the server tab */
    session *whois_sess = serv->server_session;

    /* unless this setting is on */
    if (prefs.hex_irc_whois_front)
        whois_sess = serv->front_session;

    switch (n)
    {
    case 1:
        inbound_login_start (sess, word[3], word[1]);
        /* if network is PTnet then you must get your IP address
        	from "001" server message */
        if ((strncmp(word[7], "PTnet", 5) == 0) &&
                (strncmp(word[8], "IRC", 3) == 0) &&
                (strncmp(word[9], "Network", 7) == 0) &&
                (strrchr(word[10], '@') != NULL))
        {
            serv->use_who = FALSE;
            if (prefs.hex_dcc_ip_from_server)
                inbound_foundip (sess, strrchr(word[10], '@')+1);
        }

        /* use /NICKSERV */
        if (g_ascii_strcasecmp (word[7], "DALnet") == 0 ||
                g_ascii_strcasecmp (word[7], "BRASnet") == 0)
            serv->nickservtype = 1;

        /* use /NS */
        else if (g_ascii_strcasecmp (word[7], "FreeNode") == 0)
            serv->nickservtype = 2;

        goto def;

    case 4:	/* check the ircd type */
        serv->use_listargs = FALSE;
        serv->modes_per_line = 3;		/* default to IRC RFC */
        if (strncmp (word[5], "bahamut", 7) == 0)				/* DALNet */
        {
            serv->use_listargs = TRUE;		/* use the /list args */
        } else if (strncmp (word[5], "u2.10.", 6) == 0)		/* Undernet */
        {
            serv->use_listargs = TRUE;		/* use the /list args */
            serv->modes_per_line = 6;		/* allow 6 modes per line */
        } else if (strncmp (word[5], "glx2", 4) == 0)
        {
            serv->use_listargs = TRUE;		/* use the /list args */
        }
        goto def;

    case 5:
        inbound_005 (serv, word);
        goto def;

    case 263:	/*Server load is temporarily too heavy */
        if (fe_is_chanwindow (sess->server))
        {
            fe_chan_list_end (sess->server);
            fe_message (word_eol[4] + 1, FE_MSG_ERROR);
        }
        goto def;

    case 290:	/* CAPAB reply */
        if (strstr (word_eol[1], "IDENTIFY-MSG"))
        {
            serv->have_idmsg = TRUE;
            break;
        }
        goto def;

    case 301:
        inbound_away (serv, word[4],
                      (word_eol[5][0] == ':') ? word_eol[5] + 1 : word_eol[5]);
        break;

    case 302:
        if (serv->skip_next_userhost)
        {
            char *eq = strchr (word[4], '=');
            if (eq)
            {
                *eq = 0;
                if (!serv->p_cmp (word[4] + 1, serv->nick))
                {
                    char *at = strrchr (eq + 1, '@');
                    if (at)
                        inbound_foundip (sess, at + 1);
                }
            }

            serv->skip_next_userhost = FALSE;
            break;
        }
        else goto def;

    case 303:
        word[4]++;
        notify_markonline (serv, word);
        break;

    case 305:
        inbound_uback (serv);
        goto def;

    case 306:
        inbound_uaway (serv);
        goto def;

    case 312:
        if (!serv->skip_next_whois)
            EMIT_SIGNAL (XP_TE_WHOIS3, whois_sess, word[4], word_eol[5], NULL, NULL, 0);
        else
            inbound_user_info (sess, NULL, NULL, NULL, word[5], word[4], NULL, 0xff);
        break;

    case 311:	/* WHOIS 1st line */
        serv->inside_whois = 1;
        inbound_user_info_start (sess, word[4]);
        if (!serv->skip_next_whois)
            EMIT_SIGNAL (XP_TE_WHOIS1, whois_sess, word[4], word[5],
                         word[6], word_eol[8] + 1, 0);
        else
            inbound_user_info (sess, NULL, word[5], word[6], NULL, word[4],
                               word_eol[8][0] == ':' ? word_eol[8] + 1 : word_eol[8], 0xff);
        break;

    case 314:	/* WHOWAS */
        inbound_user_info_start (sess, word[4]);
        EMIT_SIGNAL (XP_TE_WHOIS1, whois_sess, word[4], word[5],
                     word[6], word_eol[8] + 1, 0);
        break;

    case 317:
        if (!serv->skip_next_whois)
        {
            time_t timestamp = (time_t) atol (word[6]);
            long idle = atol (word[5]);
            char *tim;
            char outbuf[64];

            snprintf (outbuf, sizeof (outbuf),
                      "%02ld:%02ld:%02ld", idle / 3600, (idle / 60) % 60,
                      idle % 60);
            if (timestamp == 0)
                EMIT_SIGNAL (XP_TE_WHOIS4, whois_sess, word[4],
                             outbuf, NULL, NULL, 0);
            else
            {
                tim = ctime (&timestamp);
                tim[19] = 0; 	/* get rid of the \n */
                EMIT_SIGNAL (XP_TE_WHOIS4T, whois_sess, word[4],
                             outbuf, tim, NULL, 0);
            }
        }
        break;

    case 318:	/* END OF WHOIS */
        if (!serv->skip_next_whois)
            EMIT_SIGNAL (XP_TE_WHOIS6, whois_sess, word[4], NULL,
                         NULL, NULL, 0);
        serv->skip_next_whois = 0;
        serv->inside_whois = 0;
        break;

    case 313:
    case 319:
        if (!serv->skip_next_whois)
            EMIT_SIGNAL (XP_TE_WHOIS2, whois_sess, word[4],
                         word_eol[5] + 1, NULL, NULL, 0);
        break;

    case 307:	/* dalnet version */
    case 320:	/* :is an identified user */
        if (!serv->skip_next_whois)
            EMIT_SIGNAL (XP_TE_WHOIS_ID, whois_sess, word[4],
                         word_eol[5] + 1, NULL, NULL, 0);
        break;

    case 321:
        if (!fe_is_chanwindow (sess->server))
            EMIT_SIGNAL (XP_TE_CHANLISTHEAD, serv->server_session, NULL, NULL, NULL, NULL, 0);
        break;

    case 322:
        if (fe_is_chanwindow (sess->server))
        {
            fe_add_chan_list (sess->server, word[4], word[5], word_eol[6] + 1);
        } else
        {
            PrintTextf (serv->server_session, "%-16s %-7d %s\017\n",
                        word[4], atoi (word[5]), word_eol[6] + 1);
        }
        break;

    case 323:
        if (!fe_is_chanwindow (sess->server))
            EMIT_SIGNAL (XP_TE_SERVTEXT, serv->server_session, text, word[1], word[2], NULL, 0);
        else
            fe_chan_list_end (sess->server);
        break;

    case 324:
        sess = find_channel (serv, word[4]);
        if (!sess)
            sess = serv->server_session;
        if (sess->ignore_mode)
            sess->ignore_mode = FALSE;
        else
            EMIT_SIGNAL (XP_TE_CHANMODES, sess, word[4], word_eol[5],
                         NULL, NULL, 0);
        fe_update_mode_buttons (sess, 't', '-');
        fe_update_mode_buttons (sess, 'n', '-');
        fe_update_mode_buttons (sess, 's', '-');
        fe_update_mode_buttons (sess, 'i', '-');
        fe_update_mode_buttons (sess, 'p', '-');
        fe_update_mode_buttons (sess, 'm', '-');
        fe_update_mode_buttons (sess, 'l', '-');
        fe_update_mode_buttons (sess, 'k', '-');
        handle_mode (serv, word, word_eol, "", TRUE);
        break;

    case 329:
        sess = find_channel (serv, word[4]);
        if (sess)
        {
            if (sess->ignore_date)
                sess->ignore_date = FALSE;
            else
                channel_date (sess, word[4], word[5]);
        }
        break;

    case 330:
        if (!serv->skip_next_whois)
            EMIT_SIGNAL (XP_TE_WHOIS_AUTH, whois_sess, word[4],
                         word_eol[6] + 1, word[5], NULL, 0);
        break;

    case 332:
        inbound_topic (serv, word[4],
                       (word_eol[5][0] == ':') ? word_eol[5] + 1 : word_eol[5]);
        break;

    case 333:
        inbound_topictime (serv, word[4], word[5], atol (word[6]));
        break;

#if 0
    case 338:  /* Undernet Real user@host, Real IP */
        EMIT_SIGNAL (XP_TE_WHOIS_REALHOST, sess, word[4], word[5], word[6],
                     (word_eol[7][0]==':') ? word_eol[7]+1 : word_eol[7], 0);
        break;
#endif

    case 341:						  /* INVITE ACK */
        EMIT_SIGNAL (XP_TE_UINVITE, sess, word[4], word[5], serv->servername,
                     NULL, 0);
        break;

    case 352:						  /* WHO */
    {
        unsigned int away = 0;
        session *who_sess = find_channel (serv, word[4]);

        if (*word[9] == 'G')
            away = 1;

        inbound_user_info (sess, word[4], word[5], word[6], word[7],
                           word[8], word_eol[11], away);

        /* try to show only user initiated whos */
        if (!who_sess || !who_sess->doing_who)
            EMIT_SIGNAL (XP_TE_SERVTEXT, serv->server_session, text, word[1],
                         word[2], NULL, 0);
    }
    break;

    case 354:	/* undernet WHOX: used as a reply for irc_away_status */
    {
        unsigned int away = 0;
        session *who_sess;

        /* irc_away_status sends out a "152" */
        if (!strcmp (word[4], "152"))
        {
            who_sess = find_channel (serv, word[5]);

            if (*word[7] == 'G')
                away = 1;

            /* :SanJose.CA.us.undernet.org 354 z1 152 #zed1 z1 H@ */
            inbound_user_info (sess, word[5], 0, 0, 0, word[6], 0, away);

            /* try to show only user initiated whos */
            if (!who_sess || !who_sess->doing_who)
                EMIT_SIGNAL (XP_TE_SERVTEXT, serv->server_session, text,
                             word[1], word[2], NULL, 0);
        } else
            goto def;
    }
    break;

    case 315:						  /* END OF WHO */
    {
        session *who_sess;
        who_sess = find_channel (serv, word[4]);
        if (who_sess)
        {
            if (!who_sess->doing_who)
                EMIT_SIGNAL (XP_TE_SERVTEXT, serv->server_session, text,
                             word[1], word[2], NULL, 0);
            who_sess->doing_who = FALSE;
        } else
        {
            if (!serv->doing_dns)
                EMIT_SIGNAL (XP_TE_SERVTEXT, serv->server_session, text,
                             word[1], word[2], NULL, 0);
            serv->doing_dns = FALSE;
        }
    }
    break;

    case 348:	/* +e-list entry */
        if (!inbound_banlist (sess, atol (word[7]), word[4], word[5], word[6], TRUE))
            goto def;
        break;

    case 349:	/* end of exemption list */
        sess = find_channel (serv, word[4]);
        if (!sess)
        {
            sess = serv->front_session;
            goto def;
        }
        if (!fe_is_banwindow (sess))
            goto def;
        fe_ban_list_end (sess, TRUE);
        break;

    case 353:						  /* NAMES */
        inbound_nameslist (serv, word[5],
                           (word_eol[6][0] == ':') ? word_eol[6] + 1 : word_eol[6]);
        break;

    case 366:
        if (!inbound_nameslist_end (serv, word[4]))
            goto def;
        break;

    case 367: /* banlist entry */
        inbound_banlist (sess, atol (word[7]), word[4], word[5], word[6], FALSE);
        break;

    case 368:
        sess = find_channel (serv, word[4]);
        if (!sess)
        {
            sess = serv->front_session;
            goto def;
        }
        if (!fe_is_banwindow (sess))
            goto def;
        fe_ban_list_end (sess, FALSE);
        break;

    case 369:	/* WHOWAS end */
    case 406:	/* WHOWAS error */
        EMIT_SIGNAL (XP_TE_SERVTEXT, whois_sess, text, word[1], word[2], NULL, 0);
        serv->inside_whois = 0;
        break;

    case 372:	/* motd text */
    case 375:	/* motd start */
        if (!prefs.hex_irc_skip_motd || serv->motd_skipped)
            EMIT_SIGNAL (XP_TE_MOTD, serv->server_session, text, NULL, NULL,
                         NULL, 0);
        break;

    case 376:	/* end of motd */
    case 422:	/* motd file is missing */
        inbound_login_end (sess, text);
        break;

    case 433:	/* nickname in use */
    case 432:	/* erroneous nickname */
        if (serv->end_of_motd)
            goto def;
        inbound_next_nick (sess,  word[4]);
        break;

    case 437:
        if (serv->end_of_motd || is_channel (serv, word[4]))
            goto def;
        inbound_next_nick (sess, word[4]);
        break;

    case 471:
        EMIT_SIGNAL (XP_TE_USERLIMIT, sess, word[4], NULL, NULL, NULL, 0);
        break;

    case 473:
        EMIT_SIGNAL (XP_TE_INVITE, sess, word[4], NULL, NULL, NULL, 0);
        break;

    case 474:
        EMIT_SIGNAL (XP_TE_BANNED, sess, word[4], NULL, NULL, NULL, 0);
        break;

    case 475:
        EMIT_SIGNAL (XP_TE_KEYWORD, sess, word[4], NULL, NULL, NULL, 0);
        break;

    case 601:
        notify_set_offline (serv, word[4], FALSE);
        break;

    case 605:
        notify_set_offline (serv, word[4], TRUE);
        break;

    case 600:
    case 604:
        notify_set_online (serv, word[4]);
        break;

    case 903:	/* successful SASL auth */
    case 904:	/* aborted SASL auth */
    case 905:	/* failed SASL auth */
    case 906:	/* registration completes before SASL auth */
    case 907:	/* attempting to re-auth after a successful auth */
        EMIT_SIGNAL (XP_TE_SASLRESPONSE, serv->server_session, word[1], word[2], word[3], ++word_eol[4], 0);
        tcp_send_len (serv, "CAP END\r\n", 9);
        break;

    default:

        if (serv->inside_whois && word[4][0])
        {
            /* some unknown WHOIS reply, ircd coders make them up weekly */
            if (!serv->skip_next_whois)
                EMIT_SIGNAL (XP_TE_WHOIS_SPECIAL, whois_sess, word[4],
                             (word_eol[5][0] == ':') ? word_eol[5] + 1 : word_eol[5],
                             word[2], NULL, 0);
            return;
        }

def:
        if (is_channel (serv, word[4]))
        {
            session *realsess = find_channel (serv, word[4]);
            if (!realsess)
                realsess = serv->server_session;
            EMIT_SIGNAL (XP_TE_SERVTEXT, realsess, text, word[1], word[2], NULL, 0);
        } else
        {
            EMIT_SIGNAL (XP_TE_SERVTEXT, serv->server_session, text, word[1],
                         word[2], NULL, 0);
        }
    }
}