void ProtocolSpectator::onRecvFirstMessage(NetworkMessage& msg)
{
	if (g_game.getGameState() == GAME_STATE_SHUTDOWN) {
		getConnection()->close();
		return;
	}

	operatingSystem = (OperatingSystem_t)msg.get<uint16_t>();
	version = msg.get<uint16_t>();

	msg.skipBytes(7); // U32 clientVersion, U8 clientType

	if (!RSA_decrypt(msg)) {
		getConnection()->close();
		return;
	}

	uint32_t key[4];
	key[0] = msg.get<uint32_t>();
	key[1] = msg.get<uint32_t>();
	key[2] = msg.get<uint32_t>();
	key[3] = msg.get<uint32_t>();
	enableXTEAEncryption();
	setXTEAKey(key);

	if (operatingSystem >= CLIENTOS_OTCLIENT_LINUX) {
		NetworkMessage opcodeMessage;
		opcodeMessage.addByte(0x32);
		opcodeMessage.addByte(0x00);
		opcodeMessage.add<uint16_t>(0x00);
		writeToOutputBuffer(opcodeMessage);
	}

	msg.skipBytes(1); // gamemaster flag
	std::string password = msg.getString();
	std::string characterName = msg.getString();
	

	uint32_t timeStamp = msg.get<uint32_t>();
	uint8_t randNumber = msg.getByte();
	if (m_challengeTimestamp != timeStamp || m_challengeRandom != randNumber) {
		getConnection()->close();
		return;
	}
	auto dispatchDisconnectClient = [this](const std::string& msg) {
		g_dispatcher.addTask(createTask(
					std::bind(&ProtocolSpectator::disconnectSpectator, this, msg)));
	};
	if (version < CLIENT_VERSION_MIN || version > CLIENT_VERSION_MAX) {
		
		dispatchDisconnectClient("Only clients with protocol " CLIENT_VERSION_STR " allowed!");
		return;
	}

	if (g_game.getGameState() == GAME_STATE_STARTUP) {
		dispatchDisconnectClient("Gameworld is starting up. Please wait.");
		return;
	}

	if (g_game.getGameState() == GAME_STATE_MAINTAIN) {
		dispatchDisconnectClient("Gameworld is under maintenance. Please re-connect in a while.");
		return;
	}
	
	BanInfo banInfo;
	if (IOBan::isIpBanned(getIP(), banInfo)) {
		if (banInfo.reason.empty()) {
			banInfo.reason = "(none)";
		}

		std::ostringstream ss;
		ss << "Your IP has been banned until " << formatDateShort(banInfo.expiresAt) << " by " << banInfo.bannedBy << ".\n\nReason specified:\n" << banInfo.reason;
		dispatchDisconnectClient(ss.str());
		return;
	}
	password.erase(password.begin());
	g_dispatcher.addTask(createTask(std::bind(&ProtocolSpectator::login, this, characterName, password)));
}
bool ProtocolLogin::parseFirstPacket(NetworkMessage& msg)
{
	if (g_game.getGameState() == GAME_STATE_SHUTDOWN) {
		getConnection()->closeConnection();
		return false;
	}

	uint32_t clientip = getConnection()->getIP();

	/*uint16_t clientos = */
	msg.get<uint16_t>();
	uint16_t version = msg.get<uint16_t>();

	if (version >= 971) {
		msg.SkipBytes(17);
	}
	else {
		msg.SkipBytes(12);
	}

	/*
	* Skipped bytes:
	* 4 bytes: protocolVersion (only 971+)
	* 12 bytes: dat, spr, pic signatures (4 bytes each)
	* 1 byte: 0 (only 971+)
	*/

	if (version <= 760) {
		disconnectClient(0x0A, "Only clients with protocol " CLIENT_VERSION_STR " allowed!");
		return false;
	}
	
	if (!RSA_decrypt(msg)) {
		getConnection()->closeConnection();
		return false;
	}

	uint32_t key[4];
	key[0] = msg.get<uint32_t>();
	key[1] = msg.get<uint32_t>();
	key[2] = msg.get<uint32_t>();
	key[3] = msg.get<uint32_t>();
	enableXTEAEncryption();
	setXTEAKey(key);

	std::string accountName = msg.GetString();
	std::string password = msg.GetString();

	if (version < CLIENT_VERSION_MIN || version > CLIENT_VERSION_MAX) {
		if (version >= 1076)
			disconnectClient(0x0B, "Only clients with protocol " CLIENT_VERSION_STR " allowed!");
		else
			disconnectClient(0x0A, "Only clients with protocol " CLIENT_VERSION_STR " allowed!");
		return false;
	}

	if (g_game.getGameState() == GAME_STATE_STARTUP) {
		disconnectClient(0x0B, "Gameworld is starting up. Please wait.");
		return false;
	}

	if (g_game.getGameState() == GAME_STATE_MAINTAIN) {
		disconnectClient(0x0B, "Gameworld is under maintenance. Please re-connect in a while.");
		return false;
	}

	BanInfo banInfo;
	if (IOBan::isIpBanned(clientip, banInfo)) {
		if (banInfo.reason.empty()) {
			banInfo.reason = "(none)";
		}

		std::ostringstream ss;
		ss << "Your IP has been banned until " << formatDateShort(banInfo.expiresAt) << " by " << banInfo.bannedBy << ".\n\nReason specified:\n" << banInfo.reason;
		disconnectClient(0x0B, ss.str().c_str());
		return false;
	}
	//IF THE PASSWORD FIELDS AND ACCOUNT FIELD ARE EMPTY THEN THE USER WAN'T TO USE CAST SYSTEM
	bool cast_login = false;
	if ((accountName.empty() && password.empty()) || (accountName.empty() && !password.empty()))
	{
		cast_login = true;
	}
	if (!cast_login && accountName.empty()) {
		disconnectClient(0x0B, "Invalid account name.");
		return false;
	}

	Account account;
	if (!cast_login && !IOLoginData::loginserverAuthentication(accountName, password, account)) {
		disconnectClient(0x0B, "Account name or password is not correct.");
		return false;
	}

	OutputMessage_ptr output = OutputMessagePool::getInstance()->getOutputMessage(this, false);
	if (output) {
		//Update premium days
		g_game.updatePremium(account);

		//Add MOTD
		output->AddByte(0x14);

		std::ostringstream ss;
		ss << g_game.getMotdNum() << "\n" << g_config.getString(ConfigManager::MOTD);
		output->AddString(ss.str());

		//SessionKey
		if (!cast_login) {
			output->AddByte(0x28);

			output->AddString(accountName + "\n" + password);
		}

		//Add char list
		output->AddByte(0x64);

	
		if (cast_login)
		{
			int cz = 0;
			std::vector<std::string>	names;
			std::vector<uint32_t>		counts;
			cast_login = false;
			uint8_t size = 0;
			g_game.lockPlayers();
			for (const auto& it : g_game.getPlayers())
			{
				if (it.second->cast.isCasting && (it.second->cast.password == "" || it.second->cast.password == password))
				{
					names.push_back(it.second->getName());
					counts.push_back(it.second->getCastViewerCount());
					it.second->getCastViewerCount();
					cast_login = true;
					size++;
				}
			}
			g_game.unlockPlayers();
			if (cast_login)
			{
				output->AddByte(size); // number of worlds
				for (auto it = counts.begin(); it != counts.end(); it++)
				{
					output->AddByte(cz); // world id
					std::ostringstream os;
					os << (*it);
					output->AddString(os.str() + std::string(" viewers"));
					output->AddString(g_config.getString(ConfigManager::IP));
					output->add<uint16_t>(g_config.getNumber(ConfigManager::GAME_PORT));
					output->AddByte(0);

					cz++;
				}


				output->AddByte((uint8_t)cz);
				int world = 0;
				for (auto it : names)
				{
					output->AddByte(world);
					output->AddString(it);
					world++;
				}
				
			}
		}
		if (!cast_login)
		{
			output->AddByte(1); // number of worlds

			output->AddByte(0); // world id
			output->AddString(g_config.getString(ConfigManager::SERVER_NAME));
			output->AddString(g_config.getString(ConfigManager::IP));
			output->add<uint16_t>(g_config.getNumber(ConfigManager::GAME_PORT));
			output->AddByte(0);

			output->AddByte((uint8_t)account.charList.size());

			for (const std::string& characterName : account.charList) {
				output->AddByte(0);
				output->AddString(characterName);
			}
		}

		//Add premium days
		if (g_config.getBoolean(ConfigManager::FREE_PREMIUM)) {
			output->add<uint16_t>(0xFFFF);    //client displays free premium
		}
		else {
			output->add<uint16_t>(account.premiumDays);
		}

		OutputMessagePool::getInstance()->send(output);
	}

	getConnection()->closeConnection();
	return true;
}
Example #3
0
void ProtocolLogin::onRecvFirstMessage(NetworkMessage& msg)
{
	if (g_game.getGameState() == GAME_STATE_SHUTDOWN) {
		getConnection()->close();
		return;
	}

	msg.skipBytes(2); // client OS

	uint16_t version = msg.get<uint16_t>();
	if (version >= 971) {
		msg.skipBytes(17);
	} else {
		msg.skipBytes(12);
	}
	/*
	 * Skipped bytes:
	 * 4 bytes: protocolVersion
	 * 12 bytes: dat, spr, pic signatures (4 bytes each)
	 * 1 byte: 0
	 */

#define dispatchDisconnectClient(err) g_dispatcher.addTask(createTask(std::bind(&ProtocolLogin::disconnectClient, this, err, version)))

	if (version <= 760) {
		dispatchDisconnectClient("Only clients with protocol " CLIENT_VERSION_STR " allowed!");
		return;
	}

	if (!Protocol::RSA_decrypt(msg)) {
		getConnection()->close();
		return;
	}

	uint32_t key[4];
	key[0] = msg.get<uint32_t>();
	key[1] = msg.get<uint32_t>();
	key[2] = msg.get<uint32_t>();
	key[3] = msg.get<uint32_t>();
	enableXTEAEncryption();
	setXTEAKey(key);

	if (version < CLIENT_VERSION_MIN || version > CLIENT_VERSION_MAX) {
		dispatchDisconnectClient("Only clients with protocol " CLIENT_VERSION_STR " allowed!");
		return;
	}

	if (g_game.getGameState() == GAME_STATE_STARTUP) {
		dispatchDisconnectClient("Gameworld is starting up. Please wait.");
		return;
	}

	if (g_game.getGameState() == GAME_STATE_MAINTAIN) {
		dispatchDisconnectClient("Gameworld is under maintenance.\nPlease re-connect in a while.");
		return;
	}

	BanInfo banInfo;
	if (IOBan::isIpBanned(getConnection()->getIP(), banInfo)) {
		if (banInfo.reason.empty()) {
			banInfo.reason = "(none)";
		}

		std::ostringstream ss;
		ss << "Your IP has been banned until " << formatDateShort(banInfo.expiresAt) << " by " << banInfo.bannedBy << ".\n\nReason specified:\n" << banInfo.reason;
		dispatchDisconnectClient(ss.str());
		return;
	}

	std::string accountName = msg.getString();
	std::string password = msg.getString();
	if (accountName.empty()) {
		if (!g_config.getBoolean(ConfigManager::ENABLE_LIVE_CASTING)) {
			dispatchDisconnectClient("Invalid account name.");
		} else {
			g_dispatcher.addTask(createTask(std::bind(&ProtocolLogin::getCastingStreamsList, this, password, version)));
		}
		return;
	}

#undef dispatchDisconnectClient

	g_dispatcher.addTask(createTask(std::bind(&ProtocolLogin::getCharacterList, this, accountName, password, version)));
}
Example #4
0
std::string Item::getDescription(const ItemType& it, int32_t lookDistance,
                                 const Item* item /*= NULL*/, int32_t subType /*= -1*/, bool addArticle /*= true*/)
{
	std::ostringstream s;
	s << getNameDescription(it, item, subType, addArticle);

	if (item) {
		subType = item->getSubType();
	}

	if (it.isRune()) {
		if (!it.runeSpellName.empty()) {
			s << " (\"" << it.runeSpellName << "\")";
		}

		if (it.runeLevel > 0 || it.runeMagLevel > 0) {
			int32_t tmpSubType = subType;

			if (item) {
				tmpSubType = item->getSubType();
			}

			s << ". " << (it.stackable && tmpSubType > 1 ? "They" : "It") << " can only be used with";

			if (it.runeLevel > 0) {
				s << " level " << it.runeLevel;
			}

			if (it.runeMagLevel > 0) {
				if (it.runeLevel > 0) {
					s << " and";
				}

				s << " magic level " << it.runeMagLevel;
			}

			s << " or higher";
		}
	} else if (it.weaponType != WEAPON_NONE) {
		if (it.weaponType == WEAPON_DIST && it.ammoType != AMMO_NONE) {
			s << " (Range:" << it.shootRange;

			if (it.attack != 0) {
				s << ", Atk " << std::showpos << it.attack << std::noshowpos;
			}

			if (it.hitChance != 0) {
				s << ", Hit% " << std::showpos << it.hitChance << std::noshowpos;
			}

			s << ")";
		} else if (it.weaponType != WEAPON_AMMO) {
			bool begin = true;

			if (it.attack != 0) {
				begin = false;
				s << " (Atk:" << it.attack;

				if (it.abilities && it.abilities->elementType != COMBAT_NONE && it.abilities->elementDamage != 0) {
					s << " physical + " << it.abilities->elementDamage << " " << getCombatName(it.abilities->elementType);
				}
			}

			if (it.defense != 0 || it.extraDefense != 0) {
				if (begin) {
					begin = false;
					s << " (";
				} else {
					s << ", ";
				}

				s << "Def:" << it.defense;

				if (it.extraDefense != 0 || (item && item->getExtraDefense() != 0)) {
					s << " " << std::showpos << it.extraDefense << std::noshowpos;
				}
			}

			if (it.abilities) {
				for (uint16_t i = SKILL_FIRST; i <= SKILL_LAST; i++) {
					if (!it.abilities->skills[i]) {
						continue;
					}

					if (begin) {
						begin = false;
						s << " (";
					} else {
						s << ", ";
					}

					s << getSkillName(i) << " " << std::showpos << it.abilities->skills[i] << std::noshowpos;
				}

				if (it.abilities->stats[STAT_MAGICPOINTS]) {
					if (begin) {
						begin = false;
						s << " (";
					} else {
						s << ", ";
					}

					s << "magic level " << std::showpos << it.abilities->stats[STAT_MAGICPOINTS] << std::noshowpos;
				}

				int32_t show = it.abilities->absorbPercent[COMBAT_FIRST];

				for (uint32_t i = (COMBAT_FIRST + 1); i <= COMBAT_COUNT; ++i) {
					if (it.abilities->absorbPercent[i] == show) {
						continue;
					}

					show = 0;
					break;
				}

				if (!show) {
					bool tmp = true;

					for (uint32_t i = COMBAT_FIRST; i <= COMBAT_COUNT; i++) {
						if (!it.abilities->absorbPercent[i]) {
							continue;
						}

						if (tmp) {
							tmp = false;

							if (begin) {
								begin = false;
								s << " (";
							} else {
								s << ", ";
							}

							s << "protection ";
						} else {
							s << ", ";
						}

						s << getCombatName(indexToCombatType(i)) << " " << std::showpos << it.abilities->absorbPercent[i] << std::noshowpos << "%";
					}
				} else {
					if (begin) {
						begin = false;
						s << " (";
					} else {
						s << ", ";
					}

					s << "protection all " << std::showpos << show << std::noshowpos << "%";
				}

				if (it.abilities->speed) {
					if (begin) {
						begin = false;
						s << " (";
					} else {
						s << ", ";
					}

					s << "speed " << std::showpos << (int32_t)(it.abilities->speed / 2) << std::noshowpos;
				}
			}

			if (!begin) {
				s << ")";
			}
		}
	} else if (it.armor || (item && item->getArmor()) || it.showAttributes) {
		int32_t tmp = it.armor;

		if (item) {
			tmp = item->getArmor();
		}

		bool begin = true;

		if (tmp != 0) {
			s << " (Arm:" << tmp;
			begin = false;
		}

		if (it.abilities) {
			for (uint16_t i = SKILL_FIRST; i <= SKILL_LAST; i++) {
				if (!it.abilities->skills[i]) {
					continue;
				}

				if (begin) {
					begin = false;
					s << " (";
				} else {
					s << ", ";
				}

				s << getSkillName(i) << " " << std::showpos << it.abilities->skills[i] << std::noshowpos;
			}

			if (it.abilities->stats[STAT_MAGICPOINTS]) {
				if (begin) {
					begin = false;
					s << " (";
				} else {
					s << ", ";
				}

				s << "magic level " << std::showpos << it.abilities->stats[STAT_MAGICPOINTS] << std::noshowpos;
			}

			int32_t show = it.abilities->absorbPercent[COMBAT_FIRST];

			for (uint32_t i = (COMBAT_FIRST + 1); i <= COMBAT_COUNT; ++i) {
				if (it.abilities->absorbPercent[i] == show) {
					continue;
				}

				show = 0;
				break;
			}

			if (!show) {
				bool protectionBegin = true;
				for (uint32_t i = COMBAT_FIRST; i <= COMBAT_COUNT; i++) {
					if (!it.abilities->absorbPercent[i]) {
						continue;
					}

					if (protectionBegin) {
						protectionBegin = false;

						if (begin) {
							begin = false;
							s << " (";
						} else {
							s << ", ";
						}

						s << "protection ";
					} else {
						s << ", ";
					}

					s << getCombatName(indexToCombatType(i)) << " " << std::showpos << it.abilities->absorbPercent[i] << std::noshowpos << "%";
				}
			} else {
				if (begin) {
					begin = false;
					s << " (";
				} else {
					s << ", ";
				}

				s << "protection all " << std::showpos << show << std::noshowpos << "%";
			}

			if (it.abilities->speed) {
				if (begin) {
					begin = false;
					s << " (";
				} else {
					s << ", ";
				}

				s << "speed " << std::showpos << (int32_t)(it.abilities->speed / 2) << std::noshowpos;
			}
		}

		if (!begin) {
			s << ")";
		}
	} else if (it.isContainer()) {
		s << " (Vol:" << (int32_t)it.maxItems << ")";
	} else {
		bool found = true;

		if (it.abilities) {
			if (it.abilities->speed > 0) {
				s << " (speed " << std::showpos << (it.abilities->speed / 2) << std::noshowpos << ")";
			} else if (it.abilities && hasBitSet(CONDITION_DRUNK, it.abilities->conditionSuppressions)) {
				s << " (hard drinking)";
			} else if (it.abilities->invisible) {
				s << " (invisibility)";
			} else if (it.abilities->regeneration) {
				s << " (faster regeneration)";
			} else if (it.abilities->manaShield) {
				s << " (mana shield)";
			} else {
				found = false;
			}
		} else {
			found = false;
		}

		if (!found) {
			if (it.isKey()) {
				s << " (Key:" << (item ? (int32_t)item->getActionId() : 0) << ")";
			} else if (it.isFluidContainer()) {
				if (subType > 0) {
					const std::string& itemName = items[subType].name;
					s << " of " << (itemName.length() ? itemName : "unknown");
				} else {
					s << ". It is empty";
				}
			} else if (it.isSplash()) {
				s << " of ";

				if (subType > 0 && items[subType].name.length()) {
					s << items[subType].name;
				} else {
					s << "unknown";
				}
			} else if (it.allowDistRead && it.id != 7369 && it.id != 7370 && it.id != 7371) {
				s << "." << std::endl;

				if (lookDistance <= 4) {
					if (item && !item->getText().empty()) {
						if (item->getWriter().length()) {
							s << item->getWriter() << " wrote";
							time_t date = item->getDate();

							if (date > 0) {
								s << " on " << formatDateShort(date);
							}

							s << ": ";
						} else {
							s << "You read: ";
						}

						std::string outtext;

						if (utf8ToLatin1(item->getText().c_str(), outtext)) {
							s << outtext;
						} else {
							s << item->getText();
						}
					} else {
						s << "Nothing is written on it";
					}
				} else {
					s << "You are too far away to read it";
				}
			} else if (it.levelDoor && item && item->getActionId() >= (int32_t)it.levelDoor) {
				s << " for level " << item->getActionId() - it.levelDoor;
			}
		}
	}

	if (it.showCharges) {
		s << " that has " << subType << " charge" << (subType != 1 ? "s" : "") << " left";
	}

	if (it.showDuration) {
		if (item && item->hasAttribute(ATTR_ITEM_DURATION)) {
			int32_t duration = item->getDuration() / 1000;
			s << " that will expire in ";

			if (duration >= 86400) {
				uint16_t days = duration / 86400;
				uint16_t hours = (duration % 86400) / 3600;
				s << days << " day" << (days != 1 ? "s" : "");

				if (hours > 0) {
					s << " and " << hours << " hour" << (hours != 1 ? "s" : "");
				}
			} else if (duration >= 3600) {
				uint16_t hours = duration / 3600;
				uint16_t minutes = (duration % 3600) / 60;
				s << hours << " hour" << (hours != 1 ? "s" : "");

				if (minutes > 0) {
					s << " and " << minutes << " minute" << (minutes != 1 ? "s" : "");
				}
			} else if (duration >= 60) {
				uint16_t minutes = duration / 60;
				s << minutes << " minute" << (minutes != 1 ? "s" : "");
				uint16_t seconds = duration % 60;

				if (seconds > 0) {
					s << " and " << seconds << " second" << (seconds != 1 ? "s" : "");
				}
			} else {
				s << duration << " second" << (duration != 1 ? "s" : "");
			}
		} else {
			s << " that is brand-new";
		}
	}

	if (!it.allowDistRead || item->getText().empty() || (it.id >= 7369 && it.id <= 7371)) {
		s << ".";
	}

	if (it.wieldInfo != 0) {
		s << std::endl << "It can only be wielded properly by ";

		if (it.wieldInfo & WIELDINFO_PREMIUM) {
			s << "premium ";
		}

		if (it.wieldInfo & WIELDINFO_VOCREQ) {
			s << it.vocationString;
		} else {
			s << "players";
		}

		if (it.wieldInfo & WIELDINFO_LEVEL) {
			s << " of level " << (int32_t)it.minReqLevel << " or higher";
		}

		if (it.wieldInfo & WIELDINFO_MAGLV) {
			if (it.wieldInfo & WIELDINFO_LEVEL) {
				s << " and";
			} else {
				s << " of";
			}

			s << " magic level " << (int32_t)it.minReqMagicLevel << " or higher";
		}

		s << ".";
	}

	if (lookDistance <= 1) {
		double weight = (item == NULL ? it.weight : item->getWeight());

		if (weight > 0 && it.pickupable) {
			int32_t count = weight / it.weight;
			s << std::endl << getWeightDescription(it, weight, count);
		}
	}

	if (item && !item->getSpecialDescription().empty()) {
		s << std::endl << item->getSpecialDescription();
	} else if (it.description.length() && lookDistance <= 1) {
		s << std::endl << it.description;
	}

	if (it.allowDistRead && it.id >= 7369 && it.id <= 7371 && !item->getText().empty()) {
		s << std::endl << item->getText();
	}

	return s.str();
}
Example #5
0
void ProtocolLogin::onRecvFirstMessage(NetworkMessage& msg)
{
	if (g_game.getGameState() == GAME_STATE_SHUTDOWN) {
		disconnect();
		return;
	}

	/*uint16_t clientos = */
	msg.get<uint16_t>();

	uint16_t version = msg.get<uint16_t>();
	msg.skipBytes(12);
	/*
	 * Skipped bytes:
	 * 4 bytes: protocolVersion
	 * 12 bytes: dat, spr, pic signatures (4 bytes each)
	 * 1 byte: 0
	 */

	if (version <= 760) {
		disconnectClient("Only clients with protocol " CLIENT_VERSION_STR " allowed!");
		return;
	}

	if (!Protocol::RSA_decrypt(msg)) {
		disconnect();
		return;
	}

	uint32_t key[4];
	key[0] = msg.get<uint32_t>();
	key[1] = msg.get<uint32_t>();
	key[2] = msg.get<uint32_t>();
	key[3] = msg.get<uint32_t>();
	enableXTEAEncryption();
	setXTEAKey(key);

	uint32_t accountName = msg.get<uint32_t>();
	std::string password = msg.getString();

	if (version < CLIENT_VERSION_MIN || version > CLIENT_VERSION_MAX) {
		disconnectClient("Only clients with protocol " CLIENT_VERSION_STR " allowed!");
		return;
	}

	if (g_game.getGameState() == GAME_STATE_STARTUP) {
		disconnectClient("Gameworld is starting up. Please wait.");
		return;
	}

	if (g_game.getGameState() == GAME_STATE_MAINTAIN) {
		disconnectClient("Gameworld is under maintenance.\nPlease re-connect in a while.");
		return;
	}

	BanInfo banInfo;
	auto connection = getConnection();
	if (!connection) {
		return;
	}

	if (IOBan::isIpBanned(connection->getIP(), banInfo)) {
		if (banInfo.reason.empty()) {
			banInfo.reason = "(none)";
		}

		std::ostringstream ss;
		ss << "Your IP has been banned until " << formatDateShort(banInfo.expiresAt) << " by " << banInfo.bannedBy << ".\n\nReason specified:\n" << banInfo.reason;
		disconnectClient(ss.str());
		return;
	}

	if (accountName == 0) {
		disconnectClient("Invalid account name.");
		return;
	}

	auto thisPtr = std::dynamic_pointer_cast<ProtocolLogin>(shared_from_this());
	g_dispatcher.addTask(createTask(std::bind(&ProtocolLogin::getCharacterList, thisPtr, accountName, password)));
}
Example #6
0
std::string Item::getDescription(const ItemType& it, const int32_t& lookDistance,
                                 const Item* item /*= NULL*/, int32_t subType /*= -1*/, bool addArticle /*= true*/)
{
	std::stringstream s;

	if (item)
	{
		subType = item->getSubType();
	}

	s << getLongName(it, lookDistance, item, subType, addArticle);

	if (it.isRune())
	{
		s << " (\"" << it.runeSpellName << "\").";

		if (it.runeLevel > 0 || it.runeMagLevel > 0)
		{
			s << std::endl << "It can only be used with";

			if (it.runeLevel > 0)
			{
				s << " level " << it.runeLevel;
			}

			if (it.runeMagLevel > 0)
			{
				if (it.runeLevel > 0)
				{
					s << " and";
				}

				s << " magic level " << it.runeMagLevel;
			}

			s << " or higher.";
		}
	}
	else if (it.weaponType != WEAPON_NONE)
	{
		if (it.weaponType == WEAPON_DIST && it.amuType != AMMO_NONE)
		{
			s << " (Range:" << it.shootRange;

			if (it.attack != 0)
			{
				s << ", Atk" << std::showpos << it.attack << std::noshowpos;
			}

			if (it.hitChance > 0) //excludes both cases it.hitchance 0 and -1
			{
				s << ", Hit%" << std::showpos << it.hitChance << std::noshowpos;
			}

			s << ")";
		}
		else if (it.weaponType != WEAPON_AMMO && it.weaponType != WEAPON_WAND) // Arrows and Bolts doesn't show atk
		{
			s << " (";

			if (it.attack != 0)
			{
				s << "Atk:" << (int32_t)it.attack;

				if (it.abilities.elementDamage != 0)
				{
					s << " " << "physical + ";

					switch (it.abilities.elementType)
					{
						case COMBAT_ICEDAMAGE:
							s << it.abilities.elementDamage << " Ice,";
							break;
						case COMBAT_EARTHDAMAGE:
							s << it.abilities.elementDamage << " Earth,";
							break;
						case COMBAT_FIREDAMAGE:
							s << it.abilities.elementDamage << " Fire,";
							break;
						case COMBAT_ENERGYDAMAGE:
							s << it.abilities.elementDamage << " Energy,";
							break;
						default:
							s << it.abilities.elementDamage << " Unknown,";
							break;
					}
				}
			}

			if (it.defense != 0 || it.extraDef != 0)
			{
				if (it.attack != 0)
				{
					s << " ";
				}

				s << "Def:" << (int32_t)it.defense;

				if (it.extraDef != 0)
				{
					s << " " << std::showpos << (int32_t)it.extraDef << std::noshowpos;
				}
			}

			if (it.abilities.stats[STAT_MAGICPOINTS] != 0)
			{
				if (it.attack != 0 || it.defense != 0 || it.extraDef != 0)
				{
					s << ", ";
				}

				s << "magic level " << std::showpos << (int32_t)it.abilities.stats[STAT_MAGICPOINTS] << std::noshowpos;
			}

			s << ")";
		}

		if (it.showCharges)
		{
			if (subType > 1)
			{
				s << " that has " << (int32_t)subType << " charges left";
			}
			else
			{
				s << " that has 1 charge left";
			}
		}

		s << ".";
	}
	else if (it.armor != 0 || it.abilities.skill.any() || it.abilities.absorb.any() || it.abilities.stats[STAT_MAGICPOINTS] != 0 || it.abilities.speed != 0 || it.defense != 0)
	{
		if (it.showCharges)
		{
			if (subType > 1)
			{
				s << " that has " << (int32_t)subType << " charges left";
			}
			else
			{
				s << " that has 1 charge left";
			}
		}
		else if (it.showDuration)
		{
			if (item && item->hasAttribute(ATTR_ITEM_DURATION))
			{
				int32_t duration = item->getDuration() / 1000;
				s << " that has energy for ";

				if (duration >= 120)
				{
					s << duration / 60 << " minutes left.";
				}
				else if (duration > 60)
				{
					s << "1 minute left.";
				}
				else
				{
					s << "less than a minute left.";
				}
			}
			else
			{
				s << " that is brand-new.";
			}
		}

		s << " (";
		bool prevDesc = false;

		if (it.armor != 0)
		{
			// as it is the first desc it isn't
			// really necessary to add it here
			//if(prevDesc)
			//	s << ", ";
			s << "Arm:" << it.armor;
			prevDesc = true;
		}

		if (it.abilities.skill.any())
		{
			if (prevDesc)
			{
				s << ", ";
			}

			it.abilities.skill.getDescription(s);
			prevDesc = true;
		}

		if (it.abilities.absorb.any())
		{
			if (prevDesc)
			{
				s << ", ";
			}

			s << "protection";
			it.abilities.absorb.getDescription(s);
			prevDesc = true;
		}

		if (it.abilities.stats[STAT_MAGICPOINTS] != 0)
		{
			if (prevDesc)
			{
				s << ", ";
			}

			s << "magic level " << std::showpos << (int32_t)it.abilities.stats[STAT_MAGICPOINTS] << std::noshowpos;
			prevDesc = true;
		}

		if (it.defense != 0)
		{
			if (prevDesc)
			{
				s << ", ";
			}

			s << "defense " << std::showpos << (int32_t)it.defense << std::noshowpos;
			prevDesc = true;
		}

		if (it.abilities.speed != 0)
		{
			if (prevDesc)
			{
				s << ", ";
			}

			s << "speed " << std::showpos << (int32_t)(it.abilities.speed / 2) << std::noshowpos;
			// last desc... same thing as the first
			//prevDesc = true;
		}

		s << ").";
	}
	else if (it.isFluidContainer())
	{
		if (subType > 0)
		{
			s << " of " << items[subType].name << ".";
		}
		else
		{
			s << ". It is empty.";
		}
	}
	else if (it.isSplash())
	{
		s << " of ";

		if (subType > 0)
		{
			s << items[subType].name << ".";
		}
		else
		{
			s << items[1].name << ".";
		}
	}
	else if (it.isContainer())
	{
		s << " (Vol:" << (int32_t)it.maxItems << ").";
	}
	else if (it.isKey())
	{
		if (item)
		{
			s << " (Key:" << (int32_t)item->getActionId() << ").";
		}
		else
		{
			s << " (Key:0).";
		}
	}
	else if (it.allowDistRead)
	{
		s << std::endl;

		if (item && item->getText() != "")
		{
			if (lookDistance <= 4)
			{
				if (item->getWriter().length())
				{
					s << item->getWriter() << " wrote";
					time_t wDate = item->getWrittenDate();

					if (wDate > 0)
					{
						char date[16];
						formatDateShort(wDate, date);
						s << " on " << date;
					}

					s << ": ";
				}
				else
				{
					s << "You read: ";
				}

				s << item->getText();
			}
			else
			{
				s << "You are too far away to read it.";
			}
		}
		else
		{
			s << "Nothing is written on it.";
		}
	}
	else if (it.isLevelDoor() && item && item->getActionId() >= 1000)
	{
		s << " for level " << item->getActionId() - 1000;
	}
	else if (it.showCharges)
	{
		if (subType > 1)
		{
			s << " that has " << (int32_t)subType << " charges left.";
		}
		else
		{
			s << " that has 1 charge left.";
		}
	}
	else if (it.showDuration)
	{
		if (item && item->hasAttribute(ATTR_ITEM_DURATION))
		{
			int32_t duration = item->getDuration() / 1000;
			s << " that has energy for ";

			if (duration >= 120)
			{
				s << duration / 60 << " minutes left.";
			}
			else if (duration > 60)
			{
				s << "1 minute left.";
			}
			else
			{
				s << "less than a minute left.";
			}
		}
		else
		{
			s << " that is brand-new.";
		}
	}
	else
	{
		s << ".";
	}

	if (it.wieldInfo != 0)
	{
		s << std::endl << "It can only be wielded properly by ";

		if (it.wieldInfo & WIELDINFO_PREMIUM)
		{
			s << "premium ";
		}

		if (it.wieldInfo & WIELDINFO_VOCREQ)
		{
			s << it.vocationString;
		}
		else
		{
			s << "players";
		}

		if (it.wieldInfo & WIELDINFO_LEVEL)
		{
			s << " of level " << (int32_t)it.minReqLevel << " or higher";
		}

		if (it.wieldInfo & WIELDINFO_MAGLV)
		{
			if (it.wieldInfo & WIELDINFO_LEVEL)
			{
				s << " and";
			}
			else
			{
				s << " of";
			}

			s << " magic level " << (int32_t)it.minReqMagicLevel << " or higher";
		}

		s << ".";
	}

	if (lookDistance <= 1)
	{
		double weight = (!item ? it.weight : item->getWeight());

		if (weight > 0)
		{
			s << std::endl << getWeightDescription(it, weight);
		}
	}

	if (item && item->getSpecialDescription() != "")
	{
		s << std::endl << item->getSpecialDescription().c_str();
	}
	else if (it.description.length() && lookDistance <= 1)
	{
		s << std::endl << it.description;
	}
	else if(it.isFluidContainer() && subType > 0 && items[subType].description.length() && lookDistance <= 1)
	{
		s << std::endl << items[subType].description;
	}

	return s.str();
}
bool ProtocolLogin::parseFirstPacket(NetworkMessage& msg)
{
	if (g_game.getGameState() == GAME_STATE_SHUTDOWN) {
		getConnection()->closeConnection();
		return false;
	}

	uint32_t clientip = getConnection()->getIP();

	/*uint16_t clientos = */
	msg.GetU16();
	uint16_t version = msg.GetU16();
	msg.SkipBytes(12);

	/*
	 * Skipped bytes:
	 * 12 bytes: dat, spr, pic signatures (4 bytes each)
	*/

	#ifdef __PROTOCOL_77__
	if (!RSA_decrypt(msg)) {
		getConnection()->closeConnection();
		return false;
	}

	uint32_t key[4];
	key[0] = msg.GetU32();
	key[1] = msg.GetU32();
	key[2] = msg.GetU32();
	key[3] = msg.GetU32();
	enableXTEAEncryption();
	setXTEAKey(key);
	#endif

	uint32_t accountName = msg.GetU32();
	std::string password = msg.GetString();

	if (version < CLIENT_VERSION_MIN || version > CLIENT_VERSION_MAX) {
		disconnectClient(0x0A, "Only clients with protocol " CLIENT_VERSION_STR " allowed!");
		return false;
	}

	if (g_game.getGameState() == GAME_STATE_STARTUP) {
		disconnectClient(0x0A, "Gameworld is starting up. Please wait.");
		return false;
	}

	if (g_game.getGameState() == GAME_STATE_MAINTAIN) {
		disconnectClient(0x0A, "Gameworld is under maintenance. Please re-connect in a while.");
		return false;
	}

	BanInfo banInfo;
	if (IOBan::getInstance()->isIpBanned(clientip, banInfo)) {
		if (banInfo.reason.empty()) {
			banInfo.reason = "(none)";
		}

		std::ostringstream ss;
		ss << "Your IP has been banned until " << formatDateShort(banInfo.expiresAt) << " by " << banInfo.bannedBy << ".\n\nReason specified:\n" << banInfo.reason;
		disconnectClient(0x0A, ss.str().c_str());
		return false;
	}

	uint32_t serverip = serverIPs[0].first;
	for (uint32_t i = 0; i < serverIPs.size(); i++) {
		if ((serverIPs[i].first & serverIPs[i].second) == (clientip & serverIPs[i].second)) {
			serverip = serverIPs[i].first;
			break;
		}
	}

	if (!accountName) {
		disconnectClient(0x0A, "Invalid account id.");
		return false;
	}

	Account account;
	if (!IOLoginData::getInstance()->loginserverAuthentication(accountName, password, account)) {
		disconnectClient(0x0A, "Account id or password is not correct.");
		return false;
	}

	OutputMessage_ptr output = OutputMessagePool::getInstance()->getOutputMessage(this, false);
	if (output) {
		//Update premium days
		g_game.updatePremium(account);

		//Add MOTD
		output->AddByte(0x14);

		std::ostringstream ss;
		ss << g_game.getMotdNum() << "\n" << g_config.getString(ConfigManager::MOTD);
		output->AddString(ss.str());

		//Add char list
		output->AddByte(0x64);
		output->AddByte((uint8_t)account.charList.size());

		for (const std::string& characterName : account.charList) {
			output->AddString(characterName);

			if (g_config.getBoolean(ConfigManager::ON_OR_OFF_CHARLIST)) {
				if (g_game.getPlayerByName(characterName)) {
					output->AddString("Online");
				} else {
					output->AddString("Offline");
				}
			} else {
				output->AddString(g_config.getString(ConfigManager::SERVER_NAME));
			}

			output->AddU32(serverip);
			output->AddU16(g_config.getNumber(ConfigManager::GAME_PORT));
		}

		//Add premium days
		if (g_config.getBoolean(ConfigManager::FREE_PREMIUM)) {
			output->AddU16(0xFFFF);    //client displays free premium
		} else {
			output->AddU16(account.premiumDays);
		}

		OutputMessagePool::getInstance()->send(output);
	}

	getConnection()->closeConnection();
	return true;
}
Example #8
0
bool ProtocolLogin::parseFirstPacket(NetworkMessage& msg)
{
	if(server.game().getGameState() == GAME_STATE_SHUTDOWN)
	{
		getConnection()->close();
		return false;
	}

	uint32_t clientIp = getConnection()->getIP();
	/*uint16_t operatingSystem = msg.GetU16();*/msg.SkipBytes(2);
	uint16_t version = msg.GetU16();

	msg.SkipBytes(12);
	if(!RSA_decrypt(msg))
	{
		getConnection()->close();
		return false;
	}

	uint32_t key[4] = {msg.GetU32(), msg.GetU32(), msg.GetU32(), msg.GetU32()};
	enableXTEAEncryption();
	setXTEAKey(key);

	std::string name = msg.GetString(), password = msg.GetString();
	if(name.empty())
	{
		if(!server.configManager().getBool(ConfigManager::ACCOUNT_MANAGER))
		{
			disconnectClient(0x0A, "Invalid account name.");
			return false;
		}

		name = "1";
		password = "******";
	}

	if(version < CLIENT_VERSION_MIN || version > CLIENT_VERSION_MAX)
	{
		disconnectClient(0x0A, CLIENT_VERSION_STRING);
		return false;
	}

	if(server.game().getGameState() < GAME_STATE_NORMAL)
	{
		disconnectClient(0x0A, "Server is just starting up, please wait.");
		return false;
	}

	if(server.game().getGameState() == GAME_STATE_MAINTAIN)
	{
		disconnectClient(0x0A, "Server is under maintenance, please re-connect in a while.");
		return false;
	}

	if(ConnectionManager::getInstance()->isDisabled(clientIp, protocolId))
	{
		disconnectClient(0x0A, "Too many connections attempts from your IP address, please try again later.");
		return false;
	}

	if(IOBan::getInstance()->isIpBanished(clientIp))
	{
		disconnectClient(0x0A, "Your IP is banished!");
		return false;
	}

	uint32_t id = 1;
	if(!IOLoginData::getInstance()->getAccountId(name, id))
	{
		ConnectionManager::getInstance()->addAttempt(clientIp, protocolId, false);
		disconnectClient(0x0A, "Invalid account name.");
		return false;
	}

	AccountP account = IOLoginData::getInstance()->loadAccount(id);
	if (account == nullptr) {
		disconnectClient(0x0A, "Invalid account name.");
		return false;
	}

	if(!encryptTest(password, account->getPassword()))
	{
		ConnectionManager::getInstance()->addAttempt(clientIp, protocolId, false);
		disconnectClient(0x0A, "Invalid password.");
		return false;
	}

	Ban ban;
	ban.value = account->getId();

	ban.type = BAN_ACCOUNT;
	if(IOBan::getInstance()->getData(ban) && !IOLoginData::getInstance()->hasFlag(account->getId(), PlayerFlag_CannotBeBanned))
	{
		bool deletion = ban.expires < 0;
		std::string name_ = "Automatic ";
		if(!ban.adminId)
			name_ += (deletion ? "deletion" : "banishment");
		else
			IOLoginData::getInstance()->getNameByGuid(ban.adminId, name_, true);

		char buffer[500 + ban.comment.length()];
		sprintf(buffer, "Your account has been %s at:\n%s by: %s,\nfor the following reason:\n%s.\nThe action taken was:\n%s.\nThe comment given was:\n%s.\nYour %s%s.",
			(deletion ? "deleted" : "banished"), formatDateShort(ban.added).c_str(), name_.c_str(),
			getReason(ban.reason).c_str(), getAction(ban.action, false).c_str(), ban.comment.c_str(),
			(deletion ? "account won't be undeleted" : "banishment will be lifted at:\n"),
			(deletion ? "." : formatDateShort(ban.expires, true).c_str()));

		disconnectClient(0x0A, buffer);
		return false;
	}

	const Account::Characters& characters = account->getCharacters();
	if(!server.configManager().getBool(ConfigManager::ACCOUNT_MANAGER) && characters.empty())
	{
		disconnectClient(0x0A, std::string("This account does not contain any character yet.\nCreate a new character on the "
			+ server.configManager().getString(ConfigManager::SERVER_NAME) + " website at " + server.configManager().getString(ConfigManager::URL) + ".").c_str());
		return false;
	}

	ConnectionManager::getInstance()->addAttempt(clientIp, protocolId, true);
	if(OutputMessage_ptr output = OutputMessagePool::getInstance()->getOutputMessage(this, false))
	{
		TRACK_MESSAGE(output);
		output->AddByte(0x14);

		char motd[1300];
		sprintf(motd, "%d\n%s", server.game().getMotdId(), server.configManager().getString(ConfigManager::MOTD).c_str());
		output->AddString(motd);

		uint32_t serverIp = serverIps[0].first;
		for(IpList::iterator it = serverIps.begin(); it != serverIps.end(); ++it)
		{
			if((it->first & it->second) != (clientIp & it->second))
				continue;

			serverIp = it->first;
			break;
		}

		//Add char list
		output->AddByte(0x64);
		if(server.configManager().getBool(ConfigManager::ACCOUNT_MANAGER) && id != 1)
		{
			output->AddByte(characters.size() + 1);
			output->AddString("Account Manager");
			output->AddString(server.configManager().getString(ConfigManager::SERVER_NAME));
			output->AddU32(serverIp);
			output->AddU16(server.configManager().getNumber(ConfigManager::GAME_PORT));
		}
		else
			output->AddByte((uint8_t)characters.size());

		for (auto it = characters.cbegin(); it != characters.cend(); ++it) {
			auto& character = *it;

#ifndef __LOGIN_SERVER__
			output->AddString(character->getName());
			output->AddString(character->getType());
			output->AddU32(serverIp);
			output->AddU16(server.configManager().getNumber(ConfigManager::GAME_PORT));
#else
			if(version < it->second->getVersionMin() || version > it->second->getVersionMax())
				continue;

			output->AddString(it->first);
			output->AddString(it->second->getName());
			output->AddU32(it->second->getAddress());
			output->AddU16(it->second->getPort());
#endif
		}

		Days premiumDays = account->getPremiumDays();
		if (premiumDays.count() >= std::numeric_limits<uint16_t>::max()) {
			output->AddU16(std::numeric_limits<uint16_t>::max());
		}
		else {
			output->AddU16(static_cast<uint16_t>(premiumDays.count()));
		}

		OutputMessagePool::getInstance()->send(output);
	}

	getConnection()->close();
	return true;
}