m_turner's idea is a good start, but the magic-number-handling can all be done server-side, instead of client-side. Enter hash function. Basically, a hash function is a function in the form f(x), but the length of f(x) remains constant, no matter what x is. What that means is, you pass a value to the hash function. It returns another value, the hash digest, whose value depends on what you pass it. But, the length of what it returns is always the same, and is usually less than the length of what you pass it. So, it is possible to have two messages with the same hash digest, but it is very hard to make a message that matches to a certain hash digest.

So, what? Well, what happens is the hash digest of each message is stored with the message in the database (or in a session cookie?). If two messages have the same hash digest and are sent within an hour of each other it is almost definite that they are identical messages. If a message is deemed to be identical, it is rejected. To summarize:

  1. Bob sends a message
  2. The hash function gives us the hash digest of Bob's message
  3. The hash digest of the message is stored with the message
  4. Bob sends another message with the same hash digest, within an hour of the previous message
  5. Bob's second message is rejected
  1. Joe sends a message
  2. The hash function gives us the hash digest of Bob's message
  3. The hash digest of the message is stored with the message
  4. Joe hits the Back button and sends another message
  5. The hash function gives us the hash digest of Bob's message
  6. The hash digest of the message is stored with the message
  7. The two hash digests do not match
  8. Joe's second message is allowed
Or, like I said, we could use session cookies:
  1. Bob sends a message
  2. The hash function gives us the hash digest of Bob's message
  3. The hash digest of the message is stored in a cookie which will expire at the end of the session
  4. Bob sends another message before the session expires
  5. The hash digest of the second message is the same as the one in the session cookie
  6. Bob's message is rejected
Personally, I like session cookies, since they won't take up space in the database.
m_turner points out that not all clients that can send cookies support cookies (for example, the Java Chatterbox). However, most clients that cannot receive cookies (like the Java catbox) cannot refresh or reload or anything like that. m_turner also points out that a session cookie doesn't necessarily have a time limit. In that case, we can set the cookie to expire in, oh, say, half-an-hour from when it is saved. m_turner's final idea is to put a constraint in the database itself that doesn't allow the recipient and message to be the same for two or more messages. This works fine, but we should see which is faster: computing and then checking hash digests, or just checking the message body itself.