Пример #1
0
/**
 * ParseLineArgV
 *
 * Parses and processes a line which was sent by the server.
 *
 * @param argc number of tokens
 * @param argv the tokens
 */
bool CIRCConnection::ParseLineArgV(int argc, const char **argv) {
	CChannel *Channel;
	CClientConnection *Client;

	m_LastResponse = g_CurrentTime;

	if (argc < 2) {
		return true;
	}

	const char *Reply = argv[0];
	const char *Raw = argv[1];
	char *Nick = ::NickFromHostmask(Reply);
	int iRaw = atoi(Raw);

	bool b_Me = false;
	if (m_CurrentNick != NULL && Nick != NULL && strcasecmp(Nick, m_CurrentNick) == 0) {
		b_Me = true;
	}

	free(Nick);

	Client = GetOwner()->GetClientConnectionMultiplexer();

	// HASH values
	CHashCompare hashRaw(argv[1]);
	static CHashCompare hashPrivmsg("PRIVMSG");
	static CHashCompare hashNotice("NOTICE");
	static CHashCompare hashJoin("JOIN");
	static CHashCompare hashPart("PART");
	static CHashCompare hashKick("KICK");
	static CHashCompare hashNick("NICK");
	static CHashCompare hashQuit("QUIT");
	static CHashCompare hashMode("MODE");
	static CHashCompare hashTopic("TOPIC");
	static CHashCompare hashPong("PONG");
	// END of HASH values

	if (argc > 3 && iRaw == 433) {
		bool ReturnValue = ModuleEvent(argc, argv);

		if (ReturnValue) {
			if (GetCurrentNick() == NULL) {
				WriteLine("NICK :%s_", argv[3]);
			}

			if (m_NickCatchTimer == NULL) {
				m_NickCatchTimer = new CTimer(30, false, NickCatchTimer, this);
			}
		}

		return ReturnValue;
	} else if (argc > 3 && hashRaw == hashPrivmsg && Client == NULL) {
		const char *Host;
		const char *Dest = argv[2];
		char *Nick = ::NickFromHostmask(Reply);

		Channel = GetChannel(Dest);

		if (Channel != NULL) {
			CNick *User = Channel->GetNames()->Get(Nick);

			if (User != NULL) {
				User->SetIdleSince(g_CurrentTime);
			}

			Channel->AddBacklogLine(argv[0], argv[3]);
		}

		if (!ModuleEvent(argc, argv)) {
			free(Nick);
			return false;
		}

		/* don't log ctcp requests */
		if (argv[3][0] != '\1' && argv[3][strlen(argv[3]) - 1] != '\1' && Dest != NULL &&
				Nick != NULL && m_CurrentNick != NULL && strcasecmp(Dest, m_CurrentNick) == 0 &&
				strcasecmp(Nick, m_CurrentNick) != 0) {
			char *Dup;
			char *Delim;

			Dup = strdup(Reply);

			if (AllocFailed(Dup)) {
				free(Nick);

				return true;
			}

			Delim = strchr(Dup, '!');

			if (Delim != NULL) {
				*Delim = '\0';

				Host = Delim + 1;
			}

			GetOwner()->Log("%s (%s): %s", Dup, Delim ? Host : "<unknown host>", argv[3]);

			free(Dup);
		}

		free(Nick);

		UpdateHostHelper(Reply);

		return true;
	} else if (argc > 3 && hashRaw == hashPrivmsg && Client != NULL) {
		Channel = GetChannel(argv[2]);

		if (Channel != NULL) {
			Channel->AddBacklogLine(argv[0], argv[3]);
		}
	} else if (argc > 3 && hashRaw == hashNotice && Client == NULL) {
		const char *Dest = argv[2];
		char *Nick;
		
		if (!ModuleEvent(argc, argv)) {
			return false;
		}

		Nick = ::NickFromHostmask(Reply);

		/* don't log ctcp replies */
		if (argv[3][0] != '\1' && argv[3][strlen(argv[3]) - 1] != '\1' && Dest != NULL &&
				Nick != NULL && m_CurrentNick != NULL && strcasecmp(Dest, m_CurrentNick) == 0 &&
				strcasecmp(Nick, m_CurrentNick) != 0) {
			GetOwner()->Log("%s (notice): %s", Reply, argv[3]);
		}

		free(Nick);

		return true;
	} else if (argc > 2 && hashRaw == hashJoin) {
		if (b_Me) {
			AddChannel(argv[2]);

			/* GetOwner() can be NULL if AddChannel failed */
			if (GetOwner() != NULL && Client == NULL) {
				WriteLine("MODE %s", argv[2]);
			}
		}

		Channel = GetChannel(argv[2]);

		if (Channel != NULL) {
			Nick = NickFromHostmask(Reply);

			if (AllocFailed(Nick)) {
				return false;
			}

			Channel->AddUser(Nick, '\0');
			free(Nick);
		}

		UpdateHostHelper(Reply);
	} else if (argc > 2 && hashRaw == hashPart) {
		bool bRet = ModuleEvent(argc, argv);

		if (b_Me) {
			RemoveChannel(argv[2]);
		} else {
			Channel = GetChannel(argv[2]);

			if (Channel != NULL) {
				Nick = ::NickFromHostmask(Reply);

				if (AllocFailed(Nick)) {
					return false;
				}

				Channel->RemoveUser(Nick);

				free(Nick);
			}
		}

		UpdateHostHelper(Reply);

		return bRet;
	} else if (argc > 3 && hashRaw == hashKick) {
		bool bRet = ModuleEvent(argc, argv);

		if (m_CurrentNick != NULL && strcasecmp(argv[3], m_CurrentNick) == 0) {
			RemoveChannel(argv[2]);

			if (Client == NULL) {
				char *Dup = strdup(Reply);

				if (AllocFailed(Dup)) {
					return bRet;
				}

				char *Delim = strchr(Dup, '!');
				const char *Host = NULL;

				if (Delim) {
					*Delim = '\0';

					Host = Delim + 1;
				}

				GetOwner()->Log("%s (%s) kicked you from %s (%s)", Dup, Delim ? Host : "<unknown host>", argv[2], argc > 4 ? argv[4] : "");

				free(Dup);
			}
		} else {
			Channel = GetChannel(argv[2]);

			if (Channel != NULL) {
				Channel->RemoveUser(argv[3]);
			}
		}

		UpdateHostHelper(Reply);

		return bRet;
	} else if (argc > 2 && iRaw == 1) {
		if (Client != NULL) {
			if (strcmp(Client->GetNick(), argv[2]) != 0) {
				Client->WriteLine(":%s!%s NICK :%s", Client->GetNick(), m_Site ? m_Site : "*****@*****.**", argv[2]);
			}
		}

		free(m_CurrentNick);
		m_CurrentNick = strdup(argv[2]);

		free(m_Server);
		m_Server = strdup(Reply);
	} else if (argc > 2 && hashRaw == hashNick) {
		if (b_Me) {
			free(m_CurrentNick);
			m_CurrentNick = strdup(argv[2]);
		}

		Nick = NickFromHostmask(argv[0]);

		int i = 0;

		if (!b_Me && GetOwner()->GetClientConnectionMultiplexer() == NULL) {
			const char *AwayNick = GetOwner()->GetAwayNick();

			if (AwayNick != NULL && strcasecmp(AwayNick, Nick) == 0) {
				WriteLine("NICK %s", AwayNick);
			}
		}

		while (hash_t<CChannel *> *ChannelHash = m_Channels->Iterate(i++)) {
			ChannelHash->Value->RenameUser(Nick, argv[2]);
		}

		free(Nick);
	} else if (argc > 1 && hashRaw == hashQuit) {
		bool bRet = ModuleEvent(argc, argv);

		Nick = NickFromHostmask(argv[0]);

		int i = 0;

		while (hash_t<CChannel *> *ChannelHash = m_Channels->Iterate(i++)) {
			ChannelHash->Value->RemoveUser(Nick);
		}

		free(Nick);

		return bRet;
	} else if (argc > 1 && (iRaw == 422 || iRaw == 376)) {
		int DelayJoin = GetOwner()->GetDelayJoin();
		if (m_State != State_Connected) {
			const CVector<CModule *> *Modules = g_Bouncer->GetModules();

			for (int i = 0; i < Modules->GetLength(); i++) {
				(*Modules)[i]->ServerLogon(GetOwner()->GetUsername());
			}

			const char *ClientNick;

			if (Client != NULL) {
				ClientNick = Client->GetNick();

				if (strcmp(m_CurrentNick, ClientNick) != 0) {
					Client->ChangeNick(m_CurrentNick);
				}
			}

			GetOwner()->Log("You were successfully connected to an IRC server.");
			g_Bouncer->Log("User %s connected to an IRC server.",
				GetOwner()->GetUsername());
		}

		if (DelayJoin == 1) {
			m_DelayJoinTimer = g_Bouncer->CreateTimer(5, false, DelayJoinTimer, this);
		} else if (DelayJoin == 0) {
			JoinChannels();
		}

		if (Client == NULL) {
			bool AppendTS = (GetOwner()->GetConfig()->ReadInteger("user.ts") != 0);
			const char *AwayReason = GetOwner()->GetAwayText();

			if (AwayReason != NULL) {
				WriteLine(AppendTS ? "AWAY :%s (Away since the dawn of time)" : "AWAY :%s", AwayReason);
			}
		}

		const char *AutoModes = GetOwner()->GetAutoModes();
		const char *DropModes = GetOwner()->GetDropModes();

		if (AutoModes != NULL) {
			WriteLine("MODE %s +%s", GetCurrentNick(), AutoModes);
		}

		if (DropModes != NULL && Client == NULL) {
			WriteLine("MODE %s -%s", GetCurrentNick(), DropModes);
		}

		m_State = State_Connected;
	} else if (argc > 1 && strcasecmp(Reply, "ERROR") == 0) {
		if (strstr(Raw, "throttle") != NULL) {
			GetOwner()->ScheduleReconnect(120);
		} else {
			GetOwner()->ScheduleReconnect(5);
		}

		if (GetCurrentNick() != NULL && GetSite() != NULL) {
			g_Bouncer->LogUser(GetUser(), "Error received for user %s [%s!%s]: %s",
				GetOwner()->GetUsername(), GetCurrentNick(), GetSite(), argv[1]);
		} else {
			g_Bouncer->LogUser(GetUser(), "Error received for user %s: %s",
				GetOwner()->GetUsername(), argv[1]);
		}
	} else if (argc > 3 && iRaw == 465) {
		if (GetCurrentNick() != NULL && GetSite() != NULL) {
			g_Bouncer->LogUser(GetUser(), "G/K-line reason for user %s [%s!%s]: %s",
				GetOwner()->GetUsername(), GetCurrentNick(), GetSite(), argv[3]);
		} else {
			g_Bouncer->LogUser(GetUser(), "G/K-line reason for user %s: %s",
				GetOwner()->GetUsername(), argv[3]);
		}
	} else if (argc > 5 && iRaw == 351) {
		free(m_ServerVersion);
		m_ServerVersion = strdup(argv[3]);

		free(m_ServerFeat);
		m_ServerFeat = strdup(argv[5]);
	} else if (argc > 3 && iRaw == 5) {
		for (int i = 3; i < argc - 1; i++) {
			char *Dup = strdup(argv[i]);

			if (AllocFailed(Dup)) {
				return false;
			}

			char *Eq = strchr(Dup, '=');

			if (strcasecmp(Dup, "NAMESX") == 0) {
				WriteLine("PROTOCTL NAMESX");
			}

			char *Value;

			if (Eq) {
				*Eq = '\0';

				Value = strdup(++Eq);
			} else {
				Value = strdup("");
			}

			m_ISupport->Add(Dup, Value);

			free(Dup);
		}
	} else if (argc > 4 && iRaw == 324) {
		Channel = GetChannel(argv[3]);

		if (Channel != NULL) {
			Channel->ClearModes();
			Channel->ParseModeChange(argv[0], argv[4], argc - 5, &argv[5]);
			Channel->SetModesValid(true);
		}
	} else if (argc > 3 && hashRaw == hashMode) {
		Channel = GetChannel(argv[2]);

		if (Channel != NULL) {
			Channel->ParseModeChange(argv[0], argv[3], argc - 4, &argv[4]);
		} else if (strcmp(m_CurrentNick, argv[2]) == 0) {
			bool Flip = true, WasNull;
			const char *Modes = argv[3];
			size_t Length = strlen(Modes) + 1;

			if (m_Usermodes != NULL) {
				Length += strlen(m_Usermodes);
			}

			WasNull = (m_Usermodes != NULL) ? false : true;
			m_Usermodes = (char *)realloc(m_Usermodes, Length);

			if (AllocFailed(m_Usermodes)) {
				return false;
			}

			if (WasNull) {
				m_Usermodes[0] = '\0';
			}

			while (*Modes != '\0') {
				if (*Modes == '+') {
					Flip = true;
				} else if (*Modes == '-') {
					Flip = false;
				} else {
					if (Flip) {
						size_t Position = strlen(m_Usermodes);
						m_Usermodes[Position] = *Modes;
						m_Usermodes[Position + 1] = '\0';
					} else {
						char *CurrentModes = m_Usermodes;
						size_t a = 0;

						while (*CurrentModes != '\0') {
							*CurrentModes = m_Usermodes[a];

							if (*CurrentModes != *Modes) {
								CurrentModes++;
							}

							a++;
						}
					}
				}

				Modes++;
			}
		}

		UpdateHostHelper(Reply);
	} else if (argc > 4 && iRaw == 329) {
		Channel = GetChannel(argv[3]);

		if (Channel != NULL) {
			Channel->SetCreationTime(atoi(argv[4]));
		}
	} else if (argc > 4 && iRaw == 332) {
		Channel = GetChannel(argv[3]);

		if (Channel != NULL) {
			Channel->SetTopic(argv[4]);
		}
	} else if (argc > 5 && iRaw == 333) {
		Channel = GetChannel(argv[3]);

		if (Channel != NULL) {
			Channel->SetTopicNick(argv[4]);
			Channel->SetTopicStamp(atoi(argv[5]));
		}
	} else if (argc > 3 && iRaw == 331) {
		Channel = GetChannel(argv[3]);

		if (Channel != NULL) {
			Channel->SetNoTopic();
		}
	} else if (argc > 3 && hashRaw == hashTopic) {
		Channel = GetChannel(argv[2]);

		if (Channel != NULL) {
			Channel->SetTopic(argv[3]);
			Channel->SetTopicStamp(g_CurrentTime);
			Channel->SetTopicNick(argv[0]);
		}

		UpdateHostHelper(Reply);
	} else if (argc > 5 && iRaw == 353) {
		Channel = GetChannel(argv[4]);

		if (Channel != NULL) {
			const char *nicks;
			const char **nickv;

			nicks = ArgTokenize(argv[5]);

			if (AllocFailed(nicks)) {
				return false;
			}

			nickv = ArgToArray(nicks);

			if (AllocFailed(nickv)) {
				ArgFree(nicks);

				return false;
			}

			int nickc = ArgCount(nicks);

			for (int i = 0; i < nickc; i++) {
				char *Nick = strdup(nickv[i]);
				char *BaseNick = Nick;

				if (AllocFailed(Nick)) {
					ArgFree(nicks);

					return false;
				}

				StrTrim(Nick, ' ');

				while (IsNickPrefix(*Nick)) {
					Nick++;
				}

				char *Modes = NULL;

				if (BaseNick != Nick) {
					Modes = (char *)malloc(Nick - BaseNick + 1);

					if (!AllocFailed(Modes)) {
						strmcpy(Modes, BaseNick, Nick - BaseNick + 1);
					}
				}

				Channel->AddUser(Nick, Modes);

				free(BaseNick);
				free(Modes);
			}

			ArgFreeArray(nickv);
			ArgFree(nicks);
		}
	} else if (argc > 3 && iRaw == 366) {
		Channel = GetChannel(argv[3]);

		if (Channel != NULL) {
			Channel->SetHasNames();
		}
	} else if (argc > 9 && iRaw == 352) {
		const char *Ident = argv[4];
		const char *Host = argv[5];
		const char *Server = argv[6];
		const char *Nick = argv[7];
		const char *Realname = argv[9];
		char *Mask;

		int rc = asprintf(&Mask, "%s!%s@%s", Nick, Ident, Host);

		if (!RcFailed(rc)) {
			UpdateHostHelper(Mask);
			UpdateWhoHelper(Nick, Realname, Server);

			free(Mask);
		}
	} else if (argc > 6 && iRaw == 367) {
		Channel = GetChannel(argv[3]);

		if (Channel != NULL) {
			Channel->GetBanlist()->SetBan(argv[4], argv[5], atoi(argv[6]));
		}
	} else if (argc > 3 && iRaw == 368) {
		Channel = GetChannel(argv[3]);

		if (Channel != NULL) {
			Channel->SetHasBans();
		}
	} else if (argc > 3 && iRaw == 396) {
		free(m_Site);
		m_Site = strdup(argv[3]);

		if (AllocFailed(m_Site)) {}
	} else if (argc > 3 && hashRaw == hashPong && m_Server != NULL && strcasecmp(argv[2], m_Server) == 0 && m_EatPong) {
		m_EatPong = false;

		return false;
	} else if (argc > 3 && iRaw == 421) {
		m_FloodControl->Unplug();

		return false;
	}

	if (GetOwner() != NULL) {
		return ModuleEvent(argc, argv);
	} else {
		return true;
	}
}
Пример #2
0
/**
 * ParseLine
 *
 * Tokenizes, parses and processes a line which was sent by the IRC server.
 *
 * @param Line the line
 */
void CIRCConnection::ParseLine(const char *Line) {
	const char *RealLine = Line;
	char *Out;

	if (GetOwner() == NULL) {
		return;
	}

	if (Line[0] == ':') {
		RealLine = Line + 1;
	} else {
		RealLine = Line;
	}

	tokendata_t Args = ArgTokenize2(RealLine);
	const char **argv = ArgToArray2(Args);
	int argc = ArgCount2(Args);

	if (argv == NULL) {
		g_Bouncer->Log("ArgToArray2 returned NULL. Could not parse line (%s).", Line);

		return;
	}

	if (ParseLineArgV(argc, argv)) {
		if (strcasecmp(argv[0], "ping") == 0 && argc > 1) {
			int rc = asprintf(&Out, "PONG :%s", argv[1]);

			if (!RcFailed(rc)) {
				m_QueueHigh->QueueItem(Out);
				free(Out);
			}

			if (m_State != State_Connected) {
				m_State = State_Pong;

				if (GetOwner()->GetClientConnectionMultiplexer() == NULL) {
					WriteUnformattedLine("VERSION");
				}
			}
		} else {
			CUser *User = GetOwner();

			if (User) {
				CClientConnection *Client = User->GetClientConnectionMultiplexer();

				if (Client != NULL) {
					if (argc > 2 && strcasecmp(argv[1], "303") == 0) {
						Client->WriteLine("%s -sBNC", Line);
					} else {
						Client->WriteUnformattedLine(Line);
					}
				}
			}
		}
	}

#ifdef _WIN32
	OutputDebugString(Line);
	OutputDebugString("\n");
#endif

	//puts(Line);

	ArgFreeArray(argv);
}
Пример #3
0
	bool InterceptClientCommand(CClientConnection* Client, const char* Subcommand, int argc, const char** argv, bool NoticeUser) {
		CUser* User = Client->GetOwner();

		g_NoticeUser = NoticeUser;

		g_CurrentClient = Client;

		g_Ret = true;

		CallBinds(Type_Command, Client->GetOwner()->GetUsername(), Client, argc, argv);

		if (g_Ret && strcasecmp(Subcommand, "help") == 0 && User && User->IsAdmin()) {
			commandlist_t *Commands = Client->GetCommandList();

			AddCommand(Commands, "tcl", "Admin", "executes tcl commands", "Syntax: "
				"tcl command\nExecutes the specified tcl command.");

			g_Ret = false;
		}

		if (g_Ret && strcasecmp(Subcommand, "tcl") == 0 && User && User->IsAdmin()) {
			if (argc <= 1) {
				if (NoticeUser)
					Client->RealNotice("Syntax: tcl :command");
				else
					Client->Privmsg("Syntax: tcl :command");

				return true;
			}

			setctx(User->GetUsername());

			Tcl_DString dsScript;
			const char **argvdup;

			argvdup = ArgDupArray(argv);
			ArgRejoinArray(argvdup, 1);

			g_CurrentClient = Client;

			int Code = Tcl_EvalEx(g_Interp, Tcl_UtfToExternalDString(g_Encoding, argvdup[1], -1, &dsScript),
				-1, TCL_EVAL_GLOBAL | TCL_EVAL_DIRECT);

			ArgFreeArray(argvdup);

			Tcl_DStringFree(&dsScript);

			Tcl_Obj* Result = Tcl_GetObjResult(g_Interp);

			const char* strResult = Tcl_GetString(Result);

			if (Code == TCL_ERROR) {
				if (NoticeUser)
					Client->RealNotice("An error occured in the tcl script:");
				else
					Client->Privmsg("An error occured in the tcl script:");
			}

			if (strResult && *strResult) {
				Tcl_DString dsResult;

				char* Dup = strdup(Tcl_UtfToExternalDString(g_Encoding, strResult, -1, &dsResult));

				Tcl_DStringFree(&dsResult);

				char* token = strtok(Dup, "\n");

				while (token != NULL) {
					if (NoticeUser)
						Client->RealNotice(*token ? token : "empty string.");
					else
						Client->Privmsg(*token ? token : "empty string.");

					token = strtok(NULL, "\n");
				}

				free(Dup);
			} else {
					if (NoticeUser)
						Client->RealNotice("<no error>");
					else
						Client->Privmsg("<no error>");
			}

			g_Ret = false;
		}

		return !g_Ret;
	}