Loading...   

[Show Table of Contents]


EQEmu In-Game Mail Server

§Mail Server

Note: If your server has players using the SoF client, see Universal Chat Server

  • The EQEmu mail server is called 'mailserver', surprisingly enough. It runs as a separate process to world and zone and communicates directly with the EQ client.
  • To setup the mailserver, you must have a <mailserver> block in your eqemu_config.xml
  • E.g. If you want to run the mailserver on the computer with IP address 192.168.1.100, and want it to use UDP port 10235, your config would look like this:
<mailserver>
    <host>192.168.1.100</host>
    <port>10235</port>
</mailserver>
  • The defaults are:
<mailserver>
    <host>channels.eqemulator.net</host>
    <port>7779</port>
</mailserver>
  • You can leave the port at the default value of 7779, if you have no other programs using that port, but you must change the host address.
  • Public servers should put their external DNS name and forward the port on their firewall to the internal address of the machine running mailserver.
  • Note that this config portion must sit within the <server> config block.
  • The SQL required consists of a table:
CREATE TABLE `mail` (
  `msgid` int(10) UNSIGNED NOT NULL AUTO_INCREMENT,
  `charid` int(10) UNSIGNED NOT NULL,
  `timestamp` int(11) NOT NULL DEFAULT '0',
  `from` varchar(100) NOT NULL,
  `subject` varchar(200) NOT NULL,
  `body` text NOT NULL,
  `to` text NOT NULL,
  `status` tinyint(4) NOT NULL,
  PRIMARY KEY  (`msgid`),
  KEY `charid` (`charid`)
) ENGINE=MyISAM  DEFAULT CHARSET=utf8;
  • and a column in the character_ table:
ALTER TABLE `character_` ADD `mailkey` CHAR( 16 ) NOT NULL ;
  • The following rules govern the operation of the mail system:
RULE_BOOL ( Mail, EnableMailSystem, true) // If false, client won't bring up the Mail window.
RULE_INT ( Mail, ExpireTrash, 0) // Time in seconds. 0 will delete all messages in the trash when the mailserver starts
RULE_INT ( Mail, ExpireRead, 31536000 ) // 1 Year. Set to -1 for never
RULE_INT ( Mail, ExpireUnread, 31536000 ) // 1 Year. Set to -1 for never 
  • If Mail:EnableMailSystem is set to false, the client will not be able to bring up the mail window, and the mailserver will exit if you try to start it.
  • On startup, mail will be deleted according to the three Expiration rules, so with the defaults shown above, all mail in the 'Trash' folder will be deleted each time the mailserver starts up. Read and Unread mail will be deleted one year after being sent.
  • Expiration is done only when the mailserver first starts.
  • The following log categories are available for use in log.ini
LOG_CATEGORY( MAIL )
LOG_TYPE( MAIL, INIT, ENABLED )
LOG_TYPE( MAIL, ERROR, ENABLED )
LOG_TYPE( MAIL, CLIENT, DISABLED )
LOG_TYPE( MAIL, TRACE, DISABLED )
LOG_TYPE( MAIL, PACKETS, DISABLED)
  • By default, no messages will be produced unless an error occurs. When first implementing the mail server, you may like to enable MAIL__CLIENT and MAIL__TRACE. This will produce messages as clients connect and disconnect to the mail server, and as messages are sent and retrieved, etc.
  • Note that the Server Operator, and anybody they grant access to the database CAN READ ALL MAIL sent through the system. For this reason, players should not use in-game mail for the exchange of sensitive information. It is the responsibility of the Server Operator to ensure their players know this.
  • The mailserver uses a different set of Opcodes than world or zone. These are stored in a file called mail_opcodes.conf which should be placed in the same directory as your world/zone/eqlaunch/mailserver executables. A copy of mail_opcodes.conf is provided in the utils directory of the distribution. For reference, it contains:
#Mail opcodes
OP_MailLogin=0x01
OP_Mail=0x02
OP_MailSendHeaders=0x00
OP_MailSendBody=0x0f
OP_MailDeliveryStatus=0x12
OP_MailboxChange=0x14
OP_MailNew=0x10
  • Once you have your database, rules, log settings and mail_opcodes.conf all setup, the next step is to start the mailserver executable.
  • You should get output similar to the following:
[Debug] Starting Log: logs/eqemu_debug_mail.log
[Debug] [RULES__CHANGE] Resetting running rules to default values
[Debug] [MAIL__INIT] Starting EQEmu MailServer
[Debug] [MAIL__INIT] Log settings loaded from log.ini
[Debug] [MAIL__INIT] Connecting to MySQL...
[Status] Starting Log: logs/eqemu_mail.log
[Status] Using database 'ykesha' at localhost:3306
[Debug] [RULES__CHANGE] Loading rule set 'default' (1)
[Debug] [RULES__CHANGE] <Lots of these lines>
[Debug] [MAIL__INIT] Loaded default rule set 'default'
[Debug] [MAIL__INIT] Expiring mail...
[Debug] [MAIL__INIT] There are 0 messages in the database.
[Debug] [MAIL__INIT] Expired 0 trash messages.
[Debug] [MAIL__INIT] Expired 0 read messages.
[Debug] [MAIL__INIT] Expired 0 unread messages.
[Debug] [MAIL__INIT] Client (UDP) Mail listener started on port 10235.
[Debug] [COMMON__THREADS] Starting EQStreamFactoryWriterLoop with thread ID -1223365728
[Debug] [COMMON__THREADS] Starting EQStreamFactoryReaderLoop with thread ID -1214973024
  • If you have the default logging levels, no more messages will be produced unless an error occurs.
  • If you have MAIL__CLIENT logging set to on, you will see messages each time a player connects and disconnects:
[Debug] [MAIL__CLIENT] New Client UDP Mail connection from 192.168.1.50:62302
[Debug] [MAIL__CLIENT] New Client UDP Mail connection from 192.168.1.50:61162
[Debug] [MAIL__CLIENT] Client connection from 192.168.1.50:62302 closed.
  • Note that the client disconnects and reconnects to the mailserver each time they zone.
  • You can stop the mailserver at anytime. Doing so, or if it should crash, will not cause any problems to your world or zone processes, nor to the clients themselves, other than that they will no longer be able to use in-game mail. If the mailserver is stopped and restarted, players must zone before their clients will reconnect to the mailserver and become able to use the mail system again.
  • If MAIL__TRACE is enabled, you will see further debugging information, e.g. when a client requests mail headers, a mail body, or when they send an email.
  • All email addresses are prefixed with SOE.EQ.<your server shortname>. It is not possible to send emails between different EQEmu servers, nor between an EQEmu server and an Internet email address. Technically, both of these could be done with further development work.

§EQEmu Chat Channel Server

  • Note: If your server has players using the SoF client, see Universal Chat Server
  • For those that played on live, Chat Channels were those things such as General, NewPlayers, Antonica, Warrior, etc. that you could get autojoined to, based on your level, class or location, or you could create your own chat channels.
  • The EQEmu Chat Channel server is called 'chatserver'. It runs as a separate process to world and zone and communicates directly with the EQ client.
  • To setup the chatserver, you must have a <chatserver> block in your eqemu_config.xml

Assuming your server is for public access, you need to specify your server's DNS name and the UDP port you want chatserver to listen on.

<chatserver>
    <host>myeqemuserver.dyndns.com</host>
    <port>10234</port>
</chatserver>
  • you must also forward the port on your firewall to the internal IP address of the computer running chatserver.
  • Note that this config portion must sit within the <server> config block.
  • The SQL required consists of a table:
CREATE TABLE `chatchannels` (
  `name` varchar(64) NOT NULL,
  `owner` varchar(64) NOT NULL,
  `password` varchar(64) NOT NULL,
  `minstatus` int(5) NOT NULL DEFAULT '0',
  PRIMARY KEY  (`name`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
  • it also relies on the mailkey field introduced previously with the mailserver.
  • Chat channels are created automatically when the first player attempts to join the channel. Channels created dynamically in this way do not persist across a restart of the chatserver.
  • The reason to have a table is that there are a number of Chat Channels that the EQ client will automatically join you to (unless the option is turned off in the client). These are the channels such as General, Planes, Newplayers, etc, mentioned above.
  • To prevent a player creating one of these channels and putting a password on it, channels specified in the database are automatically created when the chatserver starts, with a password and owner that you specify. The minstatus field is the required status in the account table that a character must have in order to join that channel.
  • The following SQL inserts entries for all the channels that the Titanium client will attempt to autojoin you to.
INSERT INTO `chatchannels` (`name`, `owner`, `password`, `minstatus`) VALUES ('Newplayers', '*System*', '', 0);
INSERT INTO `chatchannels` (`name`, `owner`, `password`, `minstatus`) VALUES ('General', '*System*', '', 0);
INSERT INTO `chatchannels` (`name`, `owner`, `password`, `minstatus`) VALUES ('Warrior', '*System*', '', 0);
INSERT INTO `chatchannels` (`name`, `owner`, `password`, `minstatus`) VALUES ('Cleric', '*System*', '', 0);
INSERT INTO `chatchannels` (`name`, `owner`, `password`, `minstatus`) VALUES ('Paladin', '*System*', '', 0);
INSERT INTO `chatchannels` (`name`, `owner`, `password`, `minstatus`) VALUES ('Ranger', '*System*', '', 0);
INSERT INTO `chatchannels` (`name`, `owner`, `password`, `minstatus`) VALUES ('Shadowknight', '*System*', '', 0);
INSERT INTO `chatchannels` (`name`, `owner`, `password`, `minstatus`) VALUES ('Druid', '*System*', '', 0);
INSERT INTO `chatchannels` (`name`, `owner`, `password`, `minstatus`) VALUES ('Monk', '*System*', '', 0);
INSERT INTO `chatchannels` (`name`, `owner`, `password`, `minstatus`) VALUES ('Bard', '*System*', '', 0);
INSERT INTO `chatchannels` (`name`, `owner`, `password`, `minstatus`) VALUES ('Rogue', '*System*', '', 0);
INSERT INTO `chatchannels` (`name`, `owner`, `password`, `minstatus`) VALUES ('Shaman', '*System*', '', 0);
INSERT INTO `chatchannels` (`name`, `owner`, `password`, `minstatus`) VALUES ('Necromancer', '*System*', '', 0);
INSERT INTO `chatchannels` (`name`, `owner`, `password`, `minstatus`) VALUES ('Wizard', '*System*', '', 0);
INSERT INTO `chatchannels` (`name`, `owner`, `password`, `minstatus`) VALUES ('Magician', '*System*', '', 0);
INSERT INTO `chatchannels` (`name`, `owner`, `password`, `minstatus`) VALUES ('Enchanter', '*System*', '', 0);
INSERT INTO `chatchannels` (`name`, `owner`, `password`, `minstatus`) VALUES ('Beastlord', '*System*', '', 0);
INSERT INTO `chatchannels` (`name`, `owner`, `password`, `minstatus`) VALUES ('Berserker', '*System*', '', 0);
INSERT INTO `chatchannels` (`name`, `owner`, `password`, `minstatus`) VALUES ('Antonica', '*System*', '', 0);
INSERT INTO `chatchannels` (`name`, `owner`, `password`, `minstatus`) VALUES ('Odus', '*System*', '', 0);
INSERT INTO `chatchannels` (`name`, `owner`, `password`, `minstatus`) VALUES ('Faydwer', '*System*', '', 0);
INSERT INTO `chatchannels` (`name`, `owner`, `password`, `minstatus`) VALUES ('Kunark', '*System*', '', 0);
INSERT INTO `chatchannels` (`name`, `owner`, `password`, `minstatus`) VALUES ('Velious', '*System*', '', 0);
INSERT INTO `chatchannels` (`name`, `owner`, `password`, `minstatus`) VALUES ('Luclin', '*System*', '', 0);
INSERT INTO `chatchannels` (`name`, `owner`, `password`, `minstatus`) VALUES ('Planes', '*System*', '', 0);
INSERT INTO `chatchannels` (`name`, `owner`, `password`, `minstatus`) VALUES ('Brokenskull', '*System*', '', 0);
INSERT INTO `chatchannels` (`name`, `owner`, `password`, `minstatus`) VALUES ('Taelosia', '*System*', '', 0);
INSERT INTO `chatchannels` (`name`, `owner`, `password`, `minstatus`) VALUES ('Kuua', '*System*', '', 0);

The following rules govern the operation of the chat channel system:

RULE_INT ( Channels, RequiredStatusAdmin, 251) // Required status to administer chat channels
RULE_INT ( Channels, RequiredStatusListAll, 251) // Required status to list all chat channels
RULE_INT ( Channels, DeleteTimer, 1440) // Empty password protected channels will be deleted after this many minutes 
  • Channels:RequiredStatusAdmin specifies the account status at or above which a player (e.g. a GM) can use the moderator commands, ;moderate ;kick ;voice etc on ANY channel, not just on channels they personally created.
  • Channels:RequiredStatusListAll specifies the account status at or above which a player can issue the ;listall command to list all the channels on the server. They will not however see channels that have a minstatus higher than their account status.
  • Channels that are dynamically created by players will be deleted as soon as the last person leaves, unless a password has been set on the channel. If a password exists, the channel will only be deleted after it has been empty for Channels:DeleteTimer minutes.
  • Dynamically created channels are NEVER written to the database.
  • If a GM changes the owner or password on a permanent channel (one that exists in the chatchannels table), then that change is updated to the database.
  • The following log categories are available for use in log.ini
LOG_CATEGORY( CHANNELS )
LOG_TYPE( CHANNELS, INIT, ENABLED )
LOG_TYPE( CHANNELS, ERROR, ENABLED )
LOG_TYPE( CHANNELS, CLIENT, DISABLED )
LOG_TYPE( CHANNELS, TRACE, DISABLED )
LOG_TYPE( CHANNELS, PACKETS, DISABLED)
  • By default, no messages will be produced unless an error occurs. When first implementing the chat server, you may like to enable CHANNELS__CLIENT and CHANNELS__TRACE. This will produce messages as clients connect and disconnect to the chat server, and as channels are joined, left etc.
  • The chatserver uses the same set of Opcodes as the mailserver. These are stored in a file called mail_opcodes.conf which should be placed in the same directory as your world/zone/eqlaunch/mailserver/chatserver executables. A copy of mail_opcodes.conf is provided in the utils directory of the distribution. For reference, it contains:
#Mail and Chat Channel opcodes
OP_MailLogin=0x01
OP_Mail=0x02
OP_ChannelMessage=0x03
OP_ChannelAnnounceJoin=0x04
OP_ChannelAnnounceLeave=0x05
OP_MailSendHeaders=0x00
OP_MailSendBody=0x0f
OP_MailDeliveryStatus=0x12
OP_MailboxChange=0x14
OP_MailNew=0x10
  • Once you have your database, rules, log settings and mail_opcodes.conf all setup, the next step is to start the chatserver executable.
  • You should get output similar to the following:
[Debug] Starting Log: logs/eqemu_debug_chatchannels.log
[Debug] [RULES__CHANGE] Resetting running rules to default values
[Debug] [CHANNELS__INIT] Starting EQEmu Chat Channel Server
[Debug] [CHANNELS__INIT] Log settings loaded from log.ini
[Debug] [CHANNELS__INIT] Connecting to MySQL...
[Status] Starting Log: logs/eqemu_chatchannels.log
[Status] Using database 'ykesha' at localhost:3306
[Debug] [CHANNELS__INIT] Loaded default rule set 'default'
[Debug] [CHANNELS__INIT] Client (UDP) Chat listener started on port 10234.
[Debug] [CHANNELS__INIT] Loading chat channels from the database.
[Debug] [COMMON__THREADS] Starting EQStreamFactoryWriterLoop with thread ID -1223828576
[Debug] [COMMON__THREADS] Starting EQStreamFactoryReaderLoop with thread ID -1215435872
[Debug] [CHANNELS__TRACE] New ChatChannel created: Name: [Newplayers], Owner: [*System*], Password: [], MinStatus: 0
[Debug] [CHANNELS__TRACE] New ChatChannel created: Name: [General], Owner: [*System*], Password: [], MinStatus: 0
[Debug] [CHANNELS__TRACE] New ChatChannel created: Name: [Warrior], Owner: [*System*], Password: [], MinStatus: 0
[Debug] [CHANNELS__TRACE] New ChatChannel created: Name: [Cleric], Owner: [*System*], Password: [], MinStatus: 0
[Debug] [CHANNELS__TRACE] New ChatChannel created: Name: [Paladin], Owner: [*System*], Password: [], MinStatus: 0
[Debug] [CHANNELS__TRACE] New ChatChannel created: Name: [Ranger], Owner: [*System*], Password: [], MinStatus: 0
[Debug] [CHANNELS__TRACE] New ChatChannel created: Name: [Shadowknight], Owner: [*System*], Password: [], MinStatus: 0
[Debug] [CHANNELS__TRACE] New ChatChannel created: Name: [Druid], Owner: [*System*], Password: [], MinStatus: 0
[Debug] [CHANNELS__TRACE] New ChatChannel created: Name: [Monk], Owner: [*System*], Password: [], MinStatus: 0
[Debug] [CHANNELS__TRACE] New ChatChannel created: Name: [Bard], Owner: [*System*], Password: [], MinStatus: 0
[Debug] [CHANNELS__TRACE] New ChatChannel created: Name: [Rogue], Owner: [*System*], Password: [], MinStatus: 0
[Debug] [CHANNELS__TRACE] New ChatChannel created: Name: [Shaman], Owner: [*System*], Password: [], MinStatus: 0
[Debug] [CHANNELS__TRACE] New ChatChannel created: Name: [Necromancer], Owner: [*System*], Password: [], MinStatus: 0
[Debug] [CHANNELS__TRACE] New ChatChannel created: Name: [Wizard], Owner: [*System*], Password: [], MinStatus: 0
[Debug] [CHANNELS__TRACE] New ChatChannel created: Name: [Magician], Owner: [*System*], Password: [], MinStatus: 0
[Debug] [CHANNELS__TRACE] New ChatChannel created: Name: [Enchanter], Owner: [*System*], Password: [], MinStatus: 0
[Debug] [CHANNELS__TRACE] New ChatChannel created: Name: [Beastlord], Owner: [*System*], Password: [], MinStatus: 0
[Debug] [CHANNELS__TRACE] New ChatChannel created: Name: [Berserker], Owner: [*System*], Password: [], MinStatus: 0
[Debug] [CHANNELS__TRACE] New ChatChannel created: Name: [Antonica], Owner: [*System*], Password: [], MinStatus: 0
[Debug] [CHANNELS__TRACE] New ChatChannel created: Name: [Odus], Owner: [*System*], Password: [], MinStatus: 0
[Debug] [CHANNELS__TRACE] New ChatChannel created: Name: [Faydwer], Owner: [*System*], Password: [], MinStatus: 0
[Debug] [CHANNELS__TRACE] New ChatChannel created: Name: [Kunark], Owner: [*System*], Password: [], MinStatus: 0
[Debug] [CHANNELS__TRACE] New ChatChannel created: Name: [Velious], Owner: [*System*], Password: [], MinStatus: 0
[Debug] [CHANNELS__TRACE] New ChatChannel created: Name: [Luclin], Owner: [*System*], Password: [], MinStatus: 0
[Debug] [CHANNELS__TRACE] New ChatChannel created: Name: [Planes], Owner: [*System*], Password: [], MinStatus: 0
[Debug] [CHANNELS__TRACE] New ChatChannel created: Name: [Brokenskull], Owner: [*System*], Password: [], MinStatus: 0
[Debug] [CHANNELS__TRACE] New ChatChannel created: Name: [Taelosia], Owner: [*System*], Password: [], MinStatus: 0
[Debug] [CHANNELS__TRACE] New ChatChannel created: Name: [Kuua], Owner: [*System*], Password: [], MinStatus: 0
  • If you have the default logging levels, no more messages will be produced unless an error occurs.
  • If you have CHANNELS__CLIENT logging set to on, you will see messages each time a player connects and disconnects:
[Debug] [CHANNELS__CLIENT] New Client UDP Chat connection from 192.168.1.50:58167
[Debug] [CHANNELS__CLIENT] Client connection from 192.168.1.50:58167 closed.

Note unlike the mailserver, the client makes a connection to the chatserver the first time a character is logged in. This session that persists across zoning, unless the connection is lost.

You can stop the chatserver at anytime. Doing so, or if it should crash, will not cause any problems to your world or zone processes, nor to the clients themselves, other than that they will no longer be able to use chat channels. If the chatserveris stopped and restarted, players must zone before their clients will reconnect to the chatserver and become able to use the chat channels again.

If CHANNELS__TRACE is enabled, you will see further debugging information, e.g. when a player joins a channel, when a channel is created or deleted, when a message is sent to a channel, etc.

Client Commands

Note that some commands begin with a / while some begin with a semi-colon ';'. Technically, this is because the / commands are intepreted by the client, while the commands beginning with a semi-colon are sent to the chat server to interpret. This allows us to code our own chatserver commands. Commands beginning with a semi-colon can also be written as /chat <command>, i.e. ;oplist 1 and /chat oplist 1 are equivalent.

/join <Channelname>:<Password> 

e.g. /join general, /join Secretchannel:thepassword
You can also join multiple channels at once, e.g. /join general,secretchannel:thepassword,Warrior

/leave <Channelname> or <Channelnumber>

e.g. /leave general or /leave 2

/leaveall will remove you from all channels.

;listall If you have the required admin status, will list all chat channels currently in existence on the server.

/list will list all the channels you are joined to.

/list <Channelname> or <Channelnumber>

e.g. /list General or /list 1 will list all the players currently in that channel.

;set <Channelname> <Channelname> ...

e.g. ;set general,warrior,planes will remove you from all the channels you are in and then join you to only those channels listed.

/announce Will toggle on or off a message each time a player joins or leaves a channel that you are in.

;setowner <Playername> <Channelname or Channelnumber>

e.g. ;setowner Derision Mychannel, or ;setowner Derision 1 will, assuming you own that channel, or have admin status, transfer ownership of the channel.

;oplist <Channelname or Channelnumber>

e.g. ;oplist Mychannel, ;oplist 1 will list the owner and moderators of the specified channel.

;invite <Playername> <Channelname or Channelnumber>

e.g. ;invite Derision Mychannel, ;invite Derision 1 will, assuming you own or are a moderator of the channel, send an invite message to the player to join the channel.
Note that the invited player may join the channel without specifying the password (if one is set) one time only. I.e. if they join after being invited, and then leave, the next time they join, they must specify the channel password.

;grant <Playername> <Channelname or Channelnumber>

e.g. ;grant Derision Mychannel, or ;grant Derision 1 will, assuming you are the owner of the channel, toggle moderator powers on or off for the specified player to the given channel.

;moderate <Channelname or Channelnumber>

e.g. ;moderate Mychannel or ;moderate 1

This toggles the moderated status of the channel on or off. Only the owner, moderators and players given the right with the ;voice command may speak in the channel.

;voice <Playername> <Channelname or Channelnumber>

e.g. ;voice Derision Mychannel or ;voice Derision 1 will toggle on or off the player's ability to speak in a moderated channel.

;kick <Playername> <Channelname or Channelnumber

e.g. ;kick Derision Mychannel or ;kick Derision 1 allows a channel owner or moderator to kick a player out of a channel. There is nothing to stop the player rejoining the channel, providing they know the password if one has been set.

;password <New password> <Channelname or Channelnumber>

e.g. ;password secret Mychannel or ;password remove Mychannel allows the channel owner or moderator to set a new password, or remove the password.

;toggleinvites Allows you to toggle off or on whether you receive a message when someone invites you to a chat channel.