Skip to content
Justin Eittreim edited this page Feb 17, 2014 · 1 revision

dAmn (deviantART Message Network) is a real-time chat network developed by deviantART. Since its release with the 4th version of the deviantART website on August 7, 2004, it has been one of the most widely used forms of communication in the community.

  • August 7, 2004 deviantART launched dAmn with version 4 of their site.
  • September 19, 2005 deviantART updated the client to a new design, which was soon replaced with the "Beta version 0.4"
  • January 29, 2008 deviantART updated the back-end of their site, requiring users to visit the Chat page to establish a session variable before logging into dAmn. This broke the login mechanisms of bots briefly.
  • April 8, 2008 deviantART updated their site to version 5, with which included a new dAmn web-client labeled "Beta version 0.06".
  • October 28, 2008 deviantART changed their login process to require SSL, which broke the login mechanisms of bots briefly.
  • December 6, 2010 deviantART upgraded to a stricter web server daemon, requiring that all requests made follow RFC 1945 (lines end with a Carriage Return followed by a Newline ('\r\n') instead of just a Newline ('\n')) which broke the login mechanisms of bots briefly.
  • February 8, 2011 deviantART changed the format of their cookies, moving the authtoken to its own separate variable. This broke the login mechanisms of bots briefly.
  • February 18, 2011 deviantART changed the login process, making the main site and dAmn require two separate authtokens. The token used to login to dAmn was from then on referred to as a dAmnToken, and it had to be scraped from the Chat page prior to connecting to dAmn, and after logging into the main site. This broke the login mechanisms of bots briefly.
  • August 13, 2013 deviantART made minor changes to the login form, adding two hidden values ('validate_token' and 'validate_key') to prevent CSRF attempts. This change required a small reform in the way bots connected, and broke the login mechanisms of bots briefly.

Things like emoticons, links, and other HTML markup are encoded with what are referred to as tablumps. More information on how to parse these can be found on this page.

dAmn uses a raw plain-text protocol, which makes working with it somewhat easier as opposed to a protocol that utilizes raw bytes instead. Segments of packets are split up by Newline characters ('\n'), which will be represented as \n from here on. Packets will usually end with a Newline character immediately followed by a Null character ('\0'), which will be represented as \0 from here on.

The basic structure of a normal dAmn packet is as follows:

Commmand Parameter\narg1=value1\narg2=value2\n\0

Some packets may contain a sub-packet, which is just another packet that can be parsed the same way as its parent. Sub-packets will usually follow two Newline characters. For example:

Command Parameter\narg1=value1\narg2=value2\n\nCommand Parameter\narg1=value1\0

The easiest way to handle sub-packets is to take them out of the packet and parse them as an independent packet in the same way you would parse any other packet.

It is important to note that the Parameter and arguments are optional, as are sub-packets. In most cases where a packet contains a sub-packet, you will notice that they end with only a Null character, as opposed to a Newline character immediately followed by a Null character. It is also important to note that specific packets include a message body, which is separated in the same way as a sub-packet (two Newline characters), but is a string, and not a packet itself. The easiest way to determine whether or not the data is a sub-packet or message body, is to check whether or not it contains a Newline character. A sub-packet will always contain a Newline character, where-as a message body will not.

dAmn is hosted on chat.deviantart.com (199.15.160.100). Logging into dAmn requires a username and a dAmnToken. Information on obtaining a dAmnToken can be found on this page.

The login process is fairly simple:

If login is unsuccessful, the server will follow up the login response packet with a disconnect packet.

These are packets that the client sends to the server.

This is the handshake request packet.

dAmnClient protocol_version\nagent=useragent\n\0

The protocol_version refers to the version of the dAmn protocol that the bot or client is using. The current protocol version is 0.3. The agent argument is required. It can be anything, and is usually the name and version of the bot or client.

The server will respond with a dAmnServer packet.

After a successful handshake, the bot or client must log into the server.

login username\npk=damntoken\n\0

The username is the username of the deviantART account associated with the bot or client, while the damntoken is the dAmnToken associated with that account.

The server will respond with a login response packet.

This packet is used for joining a channel on dAmn.

join namespace\n\0

The namespace refers to the channel namespace. The format for namespaces on dAmn is chat:name, where name is the actual channel name (without the hash). For example, the namespace for #devart would be chat:devart. There is a single exception to this, which is the namespace for private chats. Private chat namespaces include the usernames of both users involved, alphabetically sorted. For example, the namespace for a private chat between SomeGuy and Jark would be pchat:jark:someguy. Notice that jark comes first, since j comes before s in the alphabet!

This is the packet used for leaving a channel on dAmn.

part namespace\n\0

The namespace refers to the channel namespace, which is the same format for all packets (as seen above, in the Join packet.)

This packet is a response to the ping packet that the server occasionally sends. Failure to send it in response to the ping packet will result in disconnection after a certain period of time.

pong\n\0

The packet is used for the majority of interactivity that the bot or client will be attempting to accomplish, which includes things like sending messages and managing a channel. The action performed is dictated by the sub-packet included in this packet.

send namespace\n\nsubpacket\0

Where namespace is the channel namespace, and subpacket is the sub-packet. Below is a list of the possible sub-packets and their formats.

This packet is used for sending a message to a channel on dAmn.

msg main\n\nmessage body

The message body refers to the message to be sent (e.g. Hello, world!)

Notice how there is no trailing Newline character, since this packet contains a message body!

This packet is used for sending an action to a channel on dAmn. An action is similar to a message, but the output format is different. Actions are the outcome of using the /me command on your client.

action main\n\nmessage body

The message body refers to the message to be sent (e.g. waves at everyone!)

Notice how there is no trailing Newline character, since this packet contains a message body!

This packet is used for sending a non-parsed message to dAmn. This is identical to the message packet, with the only difference being that the server will not parse HTML markup, emoticons, etcetera and the packet will be send as-is.

npmsg main\n\nmessage body

The message body refers to the message to be sent (e.g. Hello, world!)

Notice how there is no trailing Newline character, since this packet contains a message body!

This packet is used to promote a user in a channel.

promote username\n

Where username is the username of the user to be promoted.

Sending this packet will promote said user to the next highest privclass. Optionally, a specific privclass may be provided, which slightly changes the format:

promote username\n\nprivclass_name

Where privclass_name is the name of the privclass to promote said user to (case sensitive!).

Notice how there is no trailing Newline character, since this packet contains a message body!

This packet is used to demote a user in a channel.

demote username\n

Where username is the username of the user to be demoted.

Sending this packet will demote said user to the next lowest privclass. Optionally, a specific privclass may be provided, which slightly changes the format:

demote username\n\nprivclass_name

Where privclass_name is the name of the privclass to demote said user to (case sensitive!).

Notice how there is no trailing Newline character, since this packet contains a message body!

This packet is used to ban a user from a channel.

ban username\n

Where username is the username of the person to be banned. Sending this packet will cause dAmn to demote the user to the lowest privclass with no join privileges.

This packet is used to un-ban a user from a channel.

unban username\n

Where username is the username of the person to be un-banned. Sending this packet will cause dAmn to promote the user to the default privclass.

This packet is used for managing a channel.

admin\n\ncommand

Where command is the command to send, which is the same as if you used /admin in your client. (e.g. update privclass Visitors smilies=5)

Notice how there is no trailing Newline character, since this packet contains a message body!

This packet is used to kick a user from a channel.

kick namespace\nu=username\n\0

Where username is the username of the user to be kicked. Optionally, a reason for the kick can be specified. This requires a slight change to the format:

kick namespace\nu=username\n\nreason\0

Where reason is a message describing why they were kicked.

Notice how there is no trailing Newline character, since this packet contains a message body!

This packet is used to get certain pieces of information about a user or channel.

This packet is used to get a property for a channel, which includes the title, topic, privclasses, and members.

get namespace\np=property\n\0

Where property is the name of the property that is being requested.

This packet is used to perform a whois on a user.

get login:username\np=info\n\0

Where username is the username of the user we want information on. Notice that user namespaces are prefixed with login: instead of chat:. The property type must always be info.

This packet is used to set a property in a channel. Currently, the only properties that can be set are the title and topic.

set namespace\np=property\n\ncontent\0

Where property is the property we want to set (title or topic) and content is what we want to set it to (e.g. Welcome to my channel!)

Notice how there is no trailing Newline character, since this packet contains a message body!

This packet is used by dAmn administrators to forcibly disconnect a user from the network.

kill login:username\n\0

Where username is the username of the user to be disconnected. Optionally, you can provide a reason for the kill, or disconnect a specific connection as opposed to all of them. Keep in mind that connections are zero indexed, and as such, start at 0 instead of 1. For example, to kill only the first connection of SomeGuy with the reason Spammer!, the format would be:

kill login:SomeGuy\nconn=0\n\nSpammer!\0

Notice how there is no trailing Newline character, since this packet contains a message body!

This packet is used to gracefully disconnect from the network.

disconnect\n\0

The server will reply with a disconnect packet of its own.

These packets are sent from the server to the client.

This is the handshake response packet, which is sent in reply to a dAmnClient (handshake request) packet.

dAmnServer version\n\0

Where version is the dAmn protocol version that the server is using.

This is the response to a login request packet.

Upon an unsuccessful login, the format will be:

login username\ne=event\n\0

Where username is the username associated with the account that the bot or client is attempting to log in as, and event is a description of why the login was unsuccessful. Possible events are:

  • authentication failed: Incorrect username and/or dAmnToken.
  • not privileged: The account is banned from accessing dAmn.
  • too many connections: The account has reached the maximum amount of allowed connections on dAmn, which is currently 20. Note: Having more than two connections on dAmn can result in a warning or ban from deviantART staff under some circumstances.

On the other hand, if it was a success, the format will be:

login username\ne=ok\n\nsymbol=dA_symbol\nrealname=tagline\ngpc=server_privs\0

Where username is the username associated with the account that the bot or client is attempting to log in as, ok is the event (meaning your login was a success), dA_symbol is the symbol associated with the account (e.g. ~ or $), tagline is the tagline associated with the account, and server_privs is the global privilege class of the account on dAmn (usually guest)

It is safe to conclude that if the e variable is not ok, your login failed, and you should try again with valid credentials.

Notice how there is no trailing Newline character, since this packet contains a message body!

This is sent periodically by the server to check whether or not a client is alive.

ping\n\0

This packet is a response to a join request packet.

join namespace\ne=event\n\0

Where namespace is the channel namespace and event is a description of the result. Possible events are:

  • ok: You successfully joined the channel.
  • not privileged: You don't have privileges to join that channel.
  • bad namespace: The channel namespace is incorrectly formatted, or contains invalid characters.
  • chatroom doesn't exist: Just as it says, the channel does not exist.

This packet is a response to a part request packet.

part namespace\ne=event\n\0

Where namespace is the channel namespace and event is a description of the result. Possible events are:

  • ok: You successfully left the channel.
  • not joined: You're not in that channel!
  • bad namespace: The channel namespace is incorrectly formatted, or contains invalid characters.

Optionally, the packet can contain a reason for why you left (which is the case when you don't manually leave a channel). That reason is stored in a variable named r, and can be one of the following:

  • bad msg: You sent a packet containing invalid or unsupported characters, or an invalid sub-packet.
  • bad data: You sent an incomplete or invalid packet to dAmn.
  • msg too big: Your packet length exceeded the current limit (currently around 32768 bytes)
  • killed: reason: You were forcibly disconnected from the network with the reason specified.

This packet is sent upon joining a channel or requesting a property..

property namespace\np=property\n\ncontent\0

Where namespace is the namespace associated with which the property and data are associated, property is the name of the property (title, topic, privclasses, members) and content is the value associated with that property. Note that, other than the p variable, there are two more optional variables sent only when the property is title or topic. Those are ts and by. ts is a Unix epoch timestamp of the time said property was set, and by is the username of the person who set it.

Depending on the namespace type (chat or login), the content data changes according to the property type. For channels (namespace type of chat). If title or topic, the content is just a message body containing the content of the title/topic. If privclasses, it is a list of privclasses sorted by their order. Each line contains a privclass name and its order, in the format of order:privclass. An example would be:

99:Admins 75:Operators 50:Members 25:Guests 5:Banned

In packet form, that would be:

property chat:somewhere\np=privclasses\n\n99:Admins\n75:Operators\n50:Members\n25:Guests\n5:Banned\0

However, if the property type is members, you will receive multiple sub-packets of type member. Their format will be as follows:

member username\npc=privclass\nusericon=usericon\nsymbol=dA_symbol\nrealname=tagline\ngpc=global_privs

Where username is the member's username, privclass is the name of the privclass they are in, usericon is their avatar type, dA_symbol is their deviantART symbol (e.g. ~ or $), tagline is the tagline associated with their account, and global_privs is their privileges on dAmn (usually guest).

Alternatively, if the namespace type is login, it is a response to a whois request. This packet contains multiple sub-packets. The first is simple a message body containing their usericon, symbol, realname, and gpc. The remaining sub-packets will be of command type conn, and are information regarding each of the user's connections on dAmn. Their format will be as follows:

conn\nonline=online_time\nidle=idle_time\n\nchannels

Where online_time is a Unix epoch timestamp of when they logged in, idle_time is how many seconds they have been idle, and channels is a list of sub-packets, each containing a namespace. Their format is:

ns namespace\n\n

Where namespace is the namespace of the channel. Note that both conn and ns sub-packets are optional.

Notice how there is no trailing Newline character, since this packet contains a message body!

This packet is sent to clients to notify them of new actions or messages in a channel.

recv namespace\n\nsubpacket\0

Where namespace is the channel namespace, and subpacket is one of the sub-packets listed below.

This is received when someone sends a message to a channel, and is received by everyone in that channel.

msg main\nfrom=username\n\ncontent

Where username is who sent the message, and content is the message body.

Notice how there is no trailing Newline character, since this packet contains a message body!

This is received when someone sends an action to a channel, and is received by everyone in that channel.

action main\nfrom=username\n\ncontent

Where username is who sent the message, and content is the message body.

Notice how there is no trailing Newline character, since this packet contains a message body!

This is received when someone joins a channel, and is received by everyone in that channel.

join username\ns=shownotice\n\npc=privclass\nusericon=usericon\nsymbol=dA_symbol\nrealname=tagline\ngpc=global_privs\n

Where username is the name of the person joining, shownotice decides whether or not the client should display a message for this event, and is 1 or 0 (depending on whether or not their privclass has +shownotice or not), privclass is their privclass, usericon is their avatar type, dA_symbol is their deviantART symbol (e.g. ~ or $), tagline is their tagline, and global_privs is their privileges on dAmn (usually guest).

This is received when someone leaves a channel, and is received by everyone in that channel.

part username\n

Where username is the name of the person leaving. Optionally, if they did not leave manually, there will be a reason for their leaving set to the variable r. e.g.

part username\nr=reason\n

Possible values for reason are:

  • connection closed: The user lost their connection to dAmn, one way or another.
  • connection reset: The user's connection to dAmn was interrupted.
  • timed out: The user didn't respond to a ping packet.
  • quit: The user disconnected via the disconnect packet.
  • send error: The user disconnected abruptly during a send operation.
  • bad msg: The user sent a packet containing an invalid or unsupported character, or an invalid sub-packet.
  • bad data: The user sent an invalid packet to dAmn.
  • msg too long: The user sent a packet longer than the maximum allowed length (currently 32768 bytes)
  • killed: reason: The user was forcibly disconnected with the specified reason.

This is received when someone changes privclasses in a channel (due to a promote or demote command) and is received by everyone in that channel.

privchg username\nby=other\npc=privclass\ni=shownotice\n

Where username is the person changing privclasses, other is the person who promoted or demoted username, pc is the privclass username is now in, and shownotice tells the bot or client whether or not it should display a notice for this event, and is 1 or 0 (depending on whether or not previous privclass had +shownotice or not.)

This is received when someone performs an administrative action on a channel, and is received by everyone in the channel. The format varies depending on the type.

If the type is create or **update:

admin type\np=privclass\nby=username\nname=pc_name\nprivs=priv_string

Where type is create or update, privclass is the property type (in this situation, always privlass), username is the person who initiated the admin command, pc_name is the name of the privclass being created or updated, and priv_string is the string of privileges (e.g. +msg +join -shownotice)

If the type is rename:

admin rename\np=privclass\nby=username\nprev=prev_name\nname=pc_name

Where privclass is the property type (in this situation, always privlass), username is the person who initiated the admin command, prev_name is the name of the privclass prior to being renamed, and pc_name is the new name of the privclass.

If the type is move:

admin move\np=privclass\nby=username\nprev=prev_name\nname=pc_name\nn=usersaffected

Where privclass is the property type (in this situation, always privlass), username is the person who initiated the admin command, prev_name is the name of the privclass users are being moved from, pc_name is the name of the privclass users are being moved to, and usersaffected is the number of users affected by the move.

If the type is remove:

admin remove\np=privclass\nby=username\nname=pc_name\nn=usersaffected

Where privclass is the property type (in this situation, always privlass), username is the person who initiated the admin command, pc_name is the name of the privclass being removed, and usersaffected is the number of users affected by the removal.

If the type is show:

admin show\np=subtype\n\ncontent

Where subtype is the data being shown (users or privclass) and content is the content to be output. Depending on the subtype, it varies. If the subtype is users, each line of content will be privclass_name: userA userB userC ... where privclass_name is the name of the privclass, and the remainder is a space-separated list of the members of that privclass. If the subtype is privclass, each line of content will be privclass_name priv_string where privclass_name is the name of the privclass, and priv_string is the privileges for that privclass (e.g. +msg +join -shownotice)

If the type is privclass:

admin privclass\np=subtype\ne=error\n\ncommand

Where subtype is the type of command (privclass, users), error is what went wrong, and command is the command that the bot or client sent.

This is received if the bot or client gets kicked from a channel, and is only received by the bot/client.

kicked namespace\nby=username\n\0

Where namespace is the channel namespace, and by is the person who kicked you. Optionally, if they specified a reason for the kick, there will be a message body:

kicked namespace\nby=username\n\nreason\0

Where reason is the reason for the kick.

Notice how there is no trailing Newline character, since this packet contains a message body!

This is received when the bot or client is disconnected from dAmn.

disconnect\ne=event\n\0

Where event is a description of why you were disconnected. Possible events are:

  • ok: You were cleanly disconnected in response to a disconnect packet.
  • killed: reason: You were forcibly disconnected from the server with the specified reason.
  • no login: You failed to handshake and/or login properly.
  • shutdown: The server has been shut down.

This is received when an error occurs during the processing of a send packet..

send namespace\ne=event\n\0

Where event is a description of what went wrong. Possible values for event are:

  • nothing to send: You attempted to send an empty message.
  • not open: You are not in the channel you attempted to send to.
  • not privileged: You do not have permission to send to the target channel.
  • bad command: You attempted to send an invalid sub-packet.
  • format error: You attempted to send a packet with invalid syntax.

This is received when an error occurs while attempting to kick a user from a channel.

kick namespace\nu=username\ne=event\n\0

Where username is the person you attempted to kick and event is a description of what went wrong. Possible values for event are:

  • not privileged: You don't have privileges to kick the person from that channel.
  • no such member: The person you attempted to kick is not in that channel, or something went wrong during the kick process. (For some reason, this is a catch-all for other errors.)

This is received when something goes wrong during the process of attempting to get information about a channel.

get namespace\np=property\ne=event\n\0

Where property is the property you attempted to get and event is a description of what went wrong. Possible values for event are:

  • not joined: You aren't in the channel you attempted to get the property from.
  • unknown property: You tried to get a property that doesn't exist.

This is received when something goes wrong during the process of attempting to set information in a channel.

set namespace\np=property\ne=event\n\0

Where property is the property you attempted to set and event is a description of what went wrong. Possible values for event are:

  • not joined: You aren't in the channel you attempted to set the property in.
  • not privileged: You don't have privileges to set that property in the channel.
  • unknown property: You tried to set a property that doesn't exist.

This is received when something goes wrong while attempting to kill a user.

kill namespace\ne=event\n\0

Where event is what went wrong. Possible value for event are:

  • bad namespace: The username you specified it not currently online.
  • not privileged: You do not have permission to kill the specified login.
  • invalid connection: The connection number you specified is invalid.