예제 #1
0
파일: plexus.cpp 프로젝트: Robby-/anope
// :42X UID Adam 1 1348535644 +aow Adam 192.168.0.5 192.168.0.5 42XAAAAAB 0 192.168.0.5 :Adam
void plexus::UID::Run(MessageSource &source, const std::vector<Anope::string> &params)
{
	/* An IP of 0 means the user is spoofed */
	Anope::string ip = params[6];
	if (ip == "0")
		ip.clear();

	time_t ts;
	try
	{
		ts = convertTo<time_t>(params[2]);
	}
	catch (const ConvertException &)
	{
		ts = Anope::CurTime;
	}

	NickServ::Nick *na = NULL;
	try
	{
		if (params[8].is_pos_number_only() && convertTo<time_t>(params[8]) == ts)
			na = NickServ::FindNick(params[0]);
	}
	catch (const ConvertException &) { }
	if (params[8] != "0" && !na)
		na = NickServ::FindNick(params[8]);

	User::OnIntroduce(params[0], params[4], params[9], params[5], ip, source.GetServer(), params[10], ts, params[3], params[7], na ? na->GetAccount() : NULL);
}
예제 #2
0
파일: init.cpp 프로젝트: SaberUK/anope
/** Check if an argument was given on startup and its parameter
 * @param name The argument name
 * @param shortname A shorter name, eg --debug and -d
 * @param param A string to put the param, if any, of the argument
 * @return true if name/shortname was found, false if not
 */
static bool GetCommandLineArgument(const Anope::string &name, char shortname, Anope::string &param)
{
	param.clear();

	for (std::vector<std::pair<Anope::string, Anope::string> >::iterator it = CommandLineArguments.begin(), it_end = CommandLineArguments.end(); it != it_end; ++it)
	{
		if (it->first.equals_ci(name) || (it->first.length() == 1 && it->first[0] == shortname))
		{
			param = it->second;
			return true;
		}
	}

	return false;
}
예제 #3
0
파일: hybrid.cpp 프로젝트: SaberUK/anope
/* :0MC UID Steve 1 1350157102 +oi ~steve resolved.host 10.0.0.1 0MCAAAAAB Steve      :Mining all the time */
void hybrid::UID::Run(MessageSource &source, const std::vector<Anope::string> &params)
{
	Anope::string ip = params[6];

	if (ip == "0") /* Can be 0 for spoofed clients */
		ip.clear();

	NickServ::Nick *na = NULL;
	if (params[8] != "0" && params[8] != "*")
		na = NickServ::FindNick(params[8]);

	/* Source is always the server */
	User::OnIntroduce(params[0], params[4], params[5], "",
			ip, source.GetServer(),
			params[9], params[2].is_pos_number_only() ? convertTo<time_t>(params[2]) : 0,
			params[3], params[7], na ? na->GetAccount() : NULL);
}
예제 #4
0
파일: users.cpp 프로젝트: dream1986/anope
void User::SendMessage(const MessageSource &source, const Anope::string &msg)
{
	const char *translated_message = Language::Translate(this, msg.c_str());

	/* Send privmsg instead of notice if:
	* - UsePrivmsg is enabled
	* - The user is not registered and NSDefMsg is enabled
	* - The user is registered and has set /ns set msg on
	*/
	bool send_privmsg = Config->UsePrivmsg && ((!this->nc && Config->DefPrivmsg) || (this->nc && this->nc->HasFieldS("MSG")));
	sepstream sep(translated_message, '\n', true);
	for (Anope::string tok; sep.GetToken(tok);)
	{
		if (tok.empty())
			tok = " ";
		spacesepstream ssep(tok, true);
		Anope::string buf;
		for (Anope::string word; ssep.GetToken(word);)
		{
			Anope::string add = buf.empty() ? word : " " + word;
			if (buf.length() + add.length() > Config->LineWrap)
			{
				if (send_privmsg)
					IRCD->SendPrivmsg(source, this->GetUID(), "%s", buf.c_str());
				else
					IRCD->SendNotice(source, this->GetUID(), "%s", buf.c_str());
				buf.clear();
				add = word;
			}
			buf.append(add);
		}

		if (!buf.empty())
		{
			if (send_privmsg)
				IRCD->SendPrivmsg(source, this->GetUID(), "%s", buf.c_str());
			else
				IRCD->SendNotice(source, this->GetUID(), "%s", buf.c_str());
		}
	}
}
예제 #5
0
	void Execute(CommandSource &source, const std::vector<Anope::string> &params)
	{
		const Anope::string &subcommand = params[0];

		if (subcommand.equals_ci("ADD") && params.size() > 2)
		{
			const Anope::string &oper = params[1];
			const Anope::string &otype = params[2];

			NickAlias *na = findnick(oper);
			if (na == NULL)
				source.Reply(NICK_X_NOT_REGISTERED, oper.c_str());
			else if (na->nc->o)
				source.Reply(_("Nick \2%s\2 is already an operator."), na->nick.c_str());
			else
			{
				OperType *ot = OperType::Find(otype);
				if (ot == NULL)
					source.Reply(_("Oper type \2%s\2 has not been configured."), otype.c_str());
				else
				{
					na->nc->o = new MyOper(na->nc->display, ot);

					Log(LOG_ADMIN, source.u, this) << "ADD " << na->nick << " as type " << ot->GetName();
					source.Reply("%s (%s) added to the \2%s\2 list.", na->nick.c_str(), na->nc->display.c_str(), ot->GetName().c_str());
				}
			}
		}
		else if (subcommand.equals_ci("DEL") && params.size() > 1)
		{
			const Anope::string &oper = params[1];

			NickAlias *na = findnick(oper);
			if (na == NULL)
				source.Reply(NICK_X_NOT_REGISTERED, oper.c_str());
			else if (!na->nc || !na->nc->o)
				source.Reply(_("Nick \2%s\2 is not a services operator."), oper.c_str());
			else
			{
				delete na->nc->o;
				na->nc->o = NULL;

				Log(LOG_ADMIN, source.u, this) << "DEL " << na->nick;
				source.Reply(_("Oper privileges removed from %s (%s)."), na->nick.c_str(), na->nc->display.c_str());
			}
		}
		else if (subcommand.equals_ci("LIST"))
		{
			source.Reply(_("Name     Type"));
			for (nickcore_map::const_iterator it = NickCoreList.begin(), it_end = NickCoreList.end(); it != it_end; ++it)
			{
				NickCore *nc = it->second;

				if (!nc->o)
					continue;

				source.Reply(_("%-8s %s"), nc->o->name.c_str(), nc->o->ot->GetName().c_str());
				if (nc->o->config)
					source.Reply(_("   This oper is configured in the configuration file."));
				for (std::list<User *>::iterator uit = nc->Users.begin(); uit != nc->Users.end(); ++uit)
				{
					User *u = *uit;
					source.Reply(_("   %s is online using this oper block."), u->nick.c_str());
				}
			}
		}
		else if (subcommand.equals_ci("INFO") && params.size() > 1)
		{
			Anope::string fulltype = params[1];
			if (params.size() > 2)
				fulltype += " " + params[2];
			OperType *ot = OperType::Find(fulltype);
			if (ot == NULL)	
				source.Reply(_("Oper type \2%s\2 has not been configured."), fulltype.c_str());
			else
			{
				if (ot->GetCommands().empty())
					source.Reply(_("Opertype \2%s\2 has no allowed commands."), ot->GetName().c_str());
				else
				{
					source.Reply(_("Available commands for \2%s\2:"), ot->GetName().c_str());
					Anope::string buf;
					std::list<Anope::string> cmds = ot->GetCommands();
					for (std::list<Anope::string>::const_iterator it = cmds.begin(), it_end = cmds.end(); it != it_end; ++it)
					{
						buf += *it + " ";
						if (buf.length() > 400)
						{
							source.Reply("%s", buf.c_str());
							buf.clear();
						}
					}
					if (!buf.empty())
					{
						source.Reply("%s", buf.c_str());
						buf.clear();
					}
				}
				if (ot->GetPrivs().empty())
					source.Reply(_("Opertype \2%s\2 has no allowed privileges."), ot->GetName().c_str());
				else
				{
					source.Reply(_("Available privileges for \2%s\2:"), ot->GetName().c_str());
					Anope::string buf;
					std::list<Anope::string> privs = ot->GetPrivs();
					for (std::list<Anope::string>::const_iterator it = privs.begin(), it_end = privs.end(); it != it_end; ++it)
					{
						buf += *it + " ";
						if (buf.length() > 400)
						{
							source.Reply("%s", buf.c_str());
							buf.clear();
						}
					}
					if (!buf.empty())
					{
						source.Reply("%s", buf.c_str());
						buf.clear();
					}
				}
				if (!ot->modes.empty())
					source.Reply(_("Opertype \2%s\2 receives modes \2%s\2 once identifying."), ot->GetName().c_str(), ot->modes.c_str());
			}
		}
		else
			this->OnSyntaxError(source, subcommand);

		return;
	}
예제 #6
0
	void Execute(CommandSource &source, const std::vector<Anope::string> &params) override
	{

		const Anope::string &nick = params[0];
		Anope::string expiry = params[1];
		Anope::string reason = params.size() > 2 ? params[2] : "";
		time_t expiry_secs = Config->GetModule(this->GetOwner())->Get<time_t>("suspendexpire");

		if (Anope::ReadOnly)
			source.Reply(_("Services are in read-only mode. Any changes made may not persist."));

		if (expiry[0] != '+')
		{
			reason = expiry + " " + reason;
			reason.trim();
			expiry.clear();
		}
		else
		{
			expiry_secs = Anope::DoTime(expiry);
			if (expiry_secs == -1)
			{
				source.Reply(_("Invalid expiry time \002{0}\002."), expiry);
				return;
			}
		}

		NickServ::Nick *na = NickServ::FindNick(nick);
		if (!na)
		{
			source.Reply(_("\002{0}\002 isn't registered."), nick);
			return;
		}

		if (Config->GetModule("nickserv/main")->Get<bool>("secureadmins", "yes") && na->GetAccount()->GetOper())
		{
			source.Reply(_("You may not suspend other Services Operators' nicknames."));
			return;
		}

		NSSuspendInfo *si = na->GetAccount()->GetRef<NSSuspendInfo *>();
		if (!si)
		{
			source.Reply(_("\002%s\002 is already suspended."), na->GetAccount()->GetDisplay().c_str());
			return;
		}

		NickServ::Account *nc = na->GetAccount();

		si = Serialize::New<NSSuspendInfo *>();
		si->SetAccount(nc);
		si->SetBy(source.GetNick());
		si->SetReason(reason);
		si->SetWhen(Anope::CurTime);
		si->SetExpires(expiry_secs ? expiry_secs + Anope::CurTime : 0);

		for (NickServ::Nick *na2 : nc->GetRefs<NickServ::Nick *>())
		{
			na2->SetLastQuit(reason);

			User *u2 = User::Find(na2->GetNick(), true);
			if (u2)
			{
				u2->Logout();
				if (NickServ::service)
					NickServ::service->Collide(u2, na2);
			}
		}

		Log(LOG_ADMIN, source, this) << "for " << nick << " (" << (!reason.empty() ? reason : "No reason") << "), expires on " << (expiry_secs ? Anope::strftime(Anope::CurTime + expiry_secs) : "never");
		source.Reply(_("\002{0}\002 is now suspended."), na->GetNick());

		EventManager::Get()->Dispatch(&Event::NickSuspend::OnNickSuspend, na);
	}
예제 #7
0
void TemplateFileServer::Serve(HTTPProvider *server, const Anope::string &page_name, HTTPClient *client, HTTPMessage &message, HTTPReply &reply, Replacements &r)
{
	int fd = open((template_base + "/" + this->file_name).c_str(), O_RDONLY);
	if (fd < 0)
	{
		Log(LOG_NORMAL, "httpd") << "Error serving file " << page_name << " (" << (template_base + "/" + this->file_name) << "): " << strerror(errno);

		client->SendError(HTTP_PAGE_NOT_FOUND, "Page not found");
		return;
	}

	Anope::string buf;

	int i;
	char buffer[BUFSIZE];
	while ((i = read(fd, buffer, sizeof(buffer) - 1)) > 0)
	{
		buffer[i] = 0;
		buf += buffer;
	}

	close(fd);

	Anope::string finished;

	bool escaped = false;
	for (unsigned j = 0; j < buf.length(); ++j)
	{
		if (buf[j] == '\\' && j + 1 < buf.length() && (buf[j + 1] == '{' || buf[j + 1] == '}'))
			escaped = true;
		else if (buf[j] == '{' && !escaped)
		{
			size_t f = buf.substr(j).find('}');
			if (f == Anope::string::npos)
				break;
			const Anope::string &content = buf.substr(j + 1, f - 1);

			if (content.find("IF ") == 0)
			{
				std::vector<Anope::string> tokens;
				spacesepstream(content).GetTokens(tokens);

				if (tokens.size() == 4 && tokens[1] == "EQ")
				{
					Anope::string first = FindReplacement(r, tokens[2]), second = FindReplacement(r, tokens[3]);
					if (first.empty())
						first = tokens[2];
					if (second.empty())
						second = tokens[3];

					bool stackok = IfStack.empty() || IfStack.top();
					IfStack.push(stackok && first == second);
				}
				else if (tokens.size() == 3 && tokens[1] == "EXISTS")
				{
					bool stackok = IfStack.empty() || IfStack.top();
					IfStack.push(stackok && r.count(tokens[2]) > 0);
				}
				else
					Log() << "Invalid IF in web template " << this->file_name;
			}
			else if (content == "ELSE")
			{
				if (IfStack.empty())
					Log() << "Invalid ELSE with no stack in web template" << this->file_name;
				else
				{
					bool old = IfStack.top();
					IfStack.pop(); // Pop off previous if()
					bool stackok = IfStack.empty() || IfStack.top();
					IfStack.push(stackok && !old); // Push back the opposite of what was popped
				}
			}
			else if (content == "END IF")
			{
				if (IfStack.empty())
					Log() << "END IF with empty stack?";
				else
					IfStack.pop();
			}
			else if (content.find("FOR ") == 0)
			{
				std::vector<Anope::string> tokens;
				spacesepstream(content).GetTokens(tokens);

				if (tokens.size() != 4 || tokens[2] != "IN")
					Log() << "Invalid FOR in web template " << this->file_name;
				else
				{
					std::vector<Anope::string> temp_variables, real_variables;
					commasepstream(tokens[1]).GetTokens(temp_variables);
					commasepstream(tokens[3]).GetTokens(real_variables);

					if (temp_variables.size() != real_variables.size())
						Log() << "Invalid FOR in web template " << this->file_name << " variable mismatch";
					else
						ForLoop::Stack.push_back(ForLoop(j + f, r, temp_variables, real_variables));
				}
			}
			else if (content == "END FOR")
			{
				if (ForLoop::Stack.empty())
					Log() << "END FOR with empty stack?";
				else
				{
					ForLoop &fl = ForLoop::Stack.back();
					if (fl.finished(r))
						ForLoop::Stack.pop_back();
					else
					{
						fl.increment(r);
						if (fl.finished(r))
							ForLoop::Stack.pop_back();
						else
						{
							j = fl.start; // Move pointer back to start of the loop
							continue; // To prevent skipping over this block which doesn't exist anymore
						}
					}
				}
			}
			else if (content.find("INCLUDE ") == 0)
			{
				std::vector<Anope::string> tokens;
				spacesepstream(content).GetTokens(tokens);

				if (tokens.size() != 2)
					Log() << "Invalid INCLUDE in web template " << this->file_name;
				else
				{
					if (!finished.empty())
					{
						reply.Write(finished); // Write out what we have currently so we insert this files contents here
						finished.clear();
					}

					TemplateFileServer tfs(tokens[1]);
					tfs.Serve(server, page_name, client, message, reply, r);
				}
			}
			else
			{
				// If the if stack is empty or we are in a true statement
				bool ifok = IfStack.empty() || IfStack.top();
				bool forok = ForLoop::Stack.empty() || !ForLoop::Stack.back().finished(r);

				if (ifok && forok)
				{
					const Anope::string &replacement = FindReplacement(r, content.substr(0, f - 1));
					finished += replacement;
				}
			}

			j += f; // Skip over this whole block
		}
		else
		{
			escaped = false;

			// If the if stack is empty or we are in a true statement
			bool ifok = IfStack.empty() || IfStack.top();
			bool forok = ForLoop::Stack.empty() || !ForLoop::Stack.back().finished(r);

			if (ifok && forok)
				finished += buf[j];
		}
	}

	if (!finished.empty())
		reply.Write(finished);
}
예제 #8
0
	void Execute(CommandSource &source, const std::vector<Anope::string> &params)
	{
		const Anope::string &channel = params[0];
		const Anope::string &target = params[1];
		Anope::string what = params.size() > 2 ? params[2] : "";

		User *u = source.u;
		ChannelInfo *ci = cs_findchan(params[0]);
		if (ci == NULL)
		{
			source.Reply(CHAN_X_NOT_REGISTERED, params[0].c_str());
			return;
		}

		if (!ci->AccessFor(u).HasPriv("SET"))
		{
			source.Reply(ACCESS_DENIED);
			return;
		}
		ChannelInfo *target_ci = cs_findchan(target);
		if (!target_ci)
		{
			source.Reply(CHAN_X_NOT_REGISTERED, target.c_str());
			return;
		}
		if (!IsFounder(u, ci) || !IsFounder(u, target_ci))
		{
			source.Reply(ACCESS_DENIED);
			return;
		}

		if (what.equals_ci("ALL"))
			what.clear();

		if (what.empty())
		{
			delete target_ci;
			target_ci = new ChannelInfo(*ci);
			target_ci->name = target;
			RegisteredChannelList[target_ci->name] = target_ci;
			target_ci->c = findchan(target_ci->name);
			if (target_ci->c)
			{
				target_ci->c->ci = target_ci;

				check_modes(target_ci->c);

				ChannelMode *cm;
				if (u->FindChannel(target_ci->c) != NULL)
				{
					/* On most ircds you do not receive the admin/owner mode till its registered */
					if ((cm = ModeManager::FindChannelModeByName(CMODE_OWNER)))
						target_ci->c->SetMode(NULL, cm, u->nick);
					else if ((cm = ModeManager::FindChannelModeByName(CMODE_PROTECT)))
						target_ci->c->RemoveMode(NULL, cm, u->nick);
				}

				/* Mark the channel as persistent */
				if (target_ci->c->HasMode(CMODE_PERM))
					target_ci->SetFlag(CI_PERSIST);
				/* Persist may be in def cflags, set it here */
				else if (target_ci->HasFlag(CI_PERSIST) && (cm = ModeManager::FindChannelModeByName(CMODE_PERM)))
					target_ci->c->SetMode(NULL, CMODE_PERM);
	
				if (target_ci->bi && target_ci->c->FindUser(target_ci->bi) == NULL)
					target_ci->bi->Join(target_ci->c, &Config->BotModeList);
			}

			if (target_ci->c && !target_ci->c->topic.empty())
			{
				target_ci->last_topic = target_ci->c->topic;
				target_ci->last_topic_setter = target_ci->c->topic_setter;
				target_ci->last_topic_time = target_ci->c->topic_time;
			}
			else
				target_ci->last_topic_setter = source.owner->nick;

			FOREACH_MOD(I_OnChanRegistered, OnChanRegistered(target_ci));

			source.Reply(_("All settings from \002%s\002 have been cloned to \002%s\002"), channel.c_str(), target.c_str());
		}
		else if (what.equals_ci("ACCESS"))
		{
			for (unsigned i = 0; i < ci->GetAccessCount(); ++i)
			{
				ChanAccess *taccess = ci->GetAccess(i);
				AccessProvider *provider = taccess->provider;

				ChanAccess *newaccess = provider->Create();
				newaccess->ci = target_ci;
				newaccess->mask = taccess->mask;
				newaccess->creator = taccess->creator;
				newaccess->last_seen = taccess->last_seen;
				newaccess->created = taccess->created;
				newaccess->Unserialize(taccess->Serialize());

				target_ci->AddAccess(newaccess);
			}

			source.Reply(_("All access entries from \002%s\002 have been cloned to \002%s\002"), channel.c_str(), target.c_str());
		}
		else if (what.equals_ci("AKICK"))
		{
			target_ci->ClearAkick();
			for (unsigned i = 0; i < ci->GetAkickCount(); ++i)
			{
				AutoKick *akick = ci->GetAkick(i);
				if (akick->HasFlag(AK_ISNICK))
					target_ci->AddAkick(akick->creator, akick->nc, akick->reason, akick->addtime, akick->last_used);
				else
					target_ci->AddAkick(akick->creator, akick->mask, akick->reason, akick->addtime, akick->last_used);
			}

			source.Reply(_("All akick entries from \002%s\002 have been cloned to \002%s\002"), channel.c_str(), target.c_str());
		}
		else if (what.equals_ci("BADWORDS"))
		{
			target_ci->ClearBadWords();
			for (unsigned i = 0; i < ci->GetBadWordCount(); ++i)
			{
				BadWord *bw = ci->GetBadWord(i);
				target_ci->AddBadWord(bw->word, bw->type);
			}

			source.Reply(_("All badword entries from \002%s\002 have been cloned to \002%s\002"), channel.c_str(), target.c_str());
		}
		else
		{
			this->OnSyntaxError(source, "");
			return;
		}

		Log(LOG_COMMAND, u, this, ci) << "to clone " << (what.empty() ? "everything from it" : what) << " to " << target_ci->name;

		return;
	}
예제 #9
0
	void Execute(CommandSource &source, const std::vector<Anope::string> &params) override
	{
		const Anope::string &subcommand = params[0];

		if (subcommand.equals_ci("ADD") && params.size() > 2)
		{
			const Anope::string &oper = params[1];
			const Anope::string &otype = params[2];

			if (!source.HasPriv("operserv/oper/modify"))
			{
				source.Reply(_("Access denied. You do not have the operator privilege \002{0}\002."), "operserv/oper/modify");
				return;
			}

			NickServ::Nick *na = NickServ::FindNick(oper);
			if (na == NULL)
			{
				source.Reply(_("\002{0}\002 isn't currently online."), oper);
				return;
			}

			OperType *ot = OperType::Find(otype);
			if (ot == NULL)
			{
				source.Reply(_("Oper type \002{0}\002 has not been configured."), otype);
				return;
			}

			if (!HasPrivs(source, ot))
			{
				source.Reply(_("Access denied."));
				return;
			}

			Oper *o = na->GetAccount()->GetOper();
			if (o != nullptr)
			{
				o->Delete();
			}

			o = Serialize::New<Oper *>();
			o->SetName(na->GetAccount()->GetDisplay());
			o->SetType(ot);
			o->SetRequireOper(true);

			na->GetAccount()->SetOper(o);

			if (Anope::ReadOnly)
				source.Reply(_("Services are in read-only mode. Any changes made may not persist."));

			Log(LOG_ADMIN, source, this) << "ADD " << na->GetNick() << " as type " << ot->GetName();
			source.Reply("\002{0}\002 (\002{1}\002) added to the \002{2}\002 list.", na->GetNick(), na->GetAccount()->GetDisplay(), ot->GetName());
		}
		else if (subcommand.equals_ci("DEL") && params.size() > 1)
		{
			const Anope::string &oper = params[1];

			if (!source.HasPriv("operserv/oper/modify"))
			{
				source.Reply(_("Access denied. You do not have the operator privilege \002{0}\002."), "operserv/oper/modify");
				return;
			}

			NickServ::Nick *na = NickServ::FindNick(oper);
			if (na == nullptr || na->GetAccount() == nullptr)
			{
				source.Reply(_("\002{0}\002 isn't registered."), oper);
				return;
			}

			Oper *o = na->GetAccount()->GetOper();

			if (o == nullptr)
			{
				source.Reply(_("Nick \002{0}\002 is not a Services Operator."), oper);
				return;
			}

			if (!HasPrivs(source, o->GetType()))
			{
				source.Reply(_("Access denied."));
				return;
			}


			o->Delete();

			if (Anope::ReadOnly)
				source.Reply(_("Services are in read-only mode. Any changes made may not persist."));

			Log(LOG_ADMIN, source, this) << "DEL " << na->GetNick();
			source.Reply(_("Oper privileges removed from \002{0}\002 (\002{1}\002)."), na->GetNick(), na->GetAccount()->GetDisplay());
		}
		else if (subcommand.equals_ci("LIST"))
		{
			source.Reply(_("Name     Type"));
			for (NickServ::Account *nc : NickServ::service->GetAccountList())
			{
				Oper *oper = nc->GetOper();

				if (oper == nullptr)
					continue;

				source.Reply(Anope::printf("%-8s %s", oper->GetName().c_str(), oper->GetType()->GetName().c_str()));
				for (User *u : nc->users)
					source.Reply(_("   \002{0}\002 is online using this oper block."), u->nick);
			}
		}
		else if (subcommand.equals_ci("INFO"))
		{
			if (params.size() < 2)
			{
				source.Reply(_("Available opertypes:"));
				for (unsigned i = 0; i < Config->MyOperTypes.size(); ++i)
				{
					OperType *ot = Config->MyOperTypes[i];
					source.Reply("%s", ot->GetName().c_str());
				}
				return;
			}

			Anope::string fulltype = params[1];
			if (params.size() > 2)
				fulltype += " " + params[2];
			OperType *ot = OperType::Find(fulltype);
			if (ot == NULL)
			{
				source.Reply(_("Oper type \002{0}\002 has not been configured."), fulltype);
				return;
			}

			if (ot->GetCommands().empty())
			{
				source.Reply(_("Opertype \002{0}\002 has no allowed commands."), ot->GetName());
			}
			else
			{
				source.Reply(_("Available commands for \002{0}\002:"), ot->GetName());
				Anope::string buf;
				std::list<Anope::string> cmds = ot->GetCommands();
				for (std::list<Anope::string>::const_iterator it = cmds.begin(), it_end = cmds.end(); it != it_end; ++it)
				{
					buf += *it + " ";
					if (buf.length() > 400)
					{
						source.Reply("%s", buf.c_str());
						buf.clear();
					}
				}
				if (!buf.empty())
				{
					source.Reply("%s", buf.c_str());
					buf.clear();
				}
			}

			if (ot->GetPrivs().empty())
			{
				source.Reply(_("Opertype \002{0}\002 has no allowed privileges."), ot->GetName());
			}
			else
			{
				source.Reply(_("Available privileges for \002{0}\002:"), ot->GetName());
				Anope::string buf;
				std::list<Anope::string> privs = ot->GetPrivs();
				for (std::list<Anope::string>::const_iterator it = privs.begin(), it_end = privs.end(); it != it_end; ++it)
				{
					buf += *it + " ";
					if (buf.length() > 400)
					{
						source.Reply("%s", buf.c_str());
						buf.clear();
					}
				}
				if (!buf.empty())
				{
					source.Reply("%s", buf.c_str());
					buf.clear();
				}
			}

			if (!ot->modes.empty())
				source.Reply(_("Opertype \002{0}\002 receives modes \002{1}\002 once identified."), ot->GetName(), ot->modes);
		}
		else
		{
			this->OnSyntaxError(source, subcommand);
		}
	}