JEP-xxxx: Message update

JEP Information

Status: Jot-down
Type: Standards Track
Number: xxxx
Version: 0.0
Last Updated: 2005-12-14
JIG: Standards JIG
Approving Body: —
Supersedes: None
Superseded By: None
Short Name: updt
Schema:
Wiki Page:

Author Information

David Campey

Email: campey@informationlogistics.co.za
JID: campey@informationlogistics.co.za


Preamble


ToC


I. Introduction

Often in instant-messaging conversations, participants wish to make changes to already transmitted messages. This JEP proposes a mechanism that can be used to transmit requests for updates to previous messages.

There are three types of update identified in this JEP:

Together, these provide the necessary tools to help reduce miscommunication and bring instant messaging closer to regular conversation.

R. Requirements

This JEP describes mechanisms for handling three types of updates as described below.

R.1 Correction

Changes the body of a previously transmitted message. Used to correct for typographical and any other type of errors or simply to rephrase. This will relieve conversers of the hassle of trying to decipher a jumble of find & replace notations (e.g. s/foo/bar/, -foo+bar or foo-->bar).

R.2 Continuation

A little less obvious; allows for concatenating to other messages. This can be used to transmit phrases of a long composition, to deliver portions of a message with timing, or to add afterthoughts. Particularly useful for achieveing dramatic effect, either while reading scripts, telling jokes, or simply engaging in witty discourse.

R.3 Retraction

Removes the body of a previous message from the output window. "Oops, wrong window." et al.

D. Description

All messages sent MUST be identified using the 'id' attribute of the <message/> element.

Update directives are conveyed by adding to subsequent <message/> elements an <x/> child element qualified by the 'jabber:x:update' namespace. This information is added by the originating client based on interactions with the user.

The following attributes MUST be set on the <x/> element:

In addition, the <x/> element MAY contain XML character data that provides a natural-language description of the reason for the update.

M. Update Mechanism

M.1 Definitions:

update message
the <message/> element which contains an update directive, i.e. the element contains an <x/> child element qualified by the 'jabber:x:update' namespace.
target message
the <message/> element which has an 'id' attribute corresponding to the 'target' attribute of an update message.

M.2 Correction

On receipt of an update message of 'type' "correction", the client MUST replace the body of the target message with that of the update message. The client MAY provide a mechanism for the display of the previous states for a message.

The client SHOULD highlight the message for a short period of time after display and provide any incoming message notifications. The client could potentially check the target body against the update body and only highlight differences for additional clarity.

Subsequent references (by <message/> 'id' attribute) to either the target or correction update message MUST achieve the same result.

M.3 Continuation

On receipt of an update message of 'type' "continuation", the client MUST replace the body of the target message with the concatenation of the target message body and the update message body. The client MAY provide a mechanism for the display of the previous states for a message.

Message Update directives targeted at the components of a composite continuation message MUST only apply to those parts of the message corresponding to the target 'id'. Continuation directives targeted at non-ultimate messages in composite messages should result in insertion of the new <body /> element after the target body.

M.4 Retraction

On receipt of an update message of 'type' "retraction", the client MUST remove the body of the target message from the display. The client MAY provide a mechanism for displaying retracted messages.

The <body/> element of a retraction SHOULD contain a message which will be displayed by clients not supporting Message Updates. e.g. 'Please ignore that last message.' or 'Please ignore message: "$message-body$".'.

M.5 Time handling

Messages SHOULD be displayed in the order of the timestamp of the first <message/> element in a composite message.

If a timestamp is displayed, it SHOULD be that of the most recent <message/> in a composite message.

M.S. Discovery of Support

If messages from a Contact do not have 'id' attributes, it can be assumed that the client does not support Message Update and message updates SHOULD NOT be sent.

[maybe support should be explicitly established using Chat Session Negotiation or ServiceDisco or EntCap]

Note: clients that don't support Message Updates will simply ignore the <x/> element and the messages will still be displayed in a sensible fashion.

X. Example: Act 2 Scene 2

<message from='juliet@capulet.com/balcony' to='romeo@montague.net' id='0000'>
  <body>O Romeo</body>
</message>
Juliet: O Romeo

<message from='juliet@capulet.com/balcony' to='romeo@montague.net' id='0001'>
  <body>, Romeo!</body>
  <x target='0000' type='continuation'/>
</message>
Juliet: O Romeo, Romeo!

<message from='juliet@capulet.com/balcony' to='romeo@montague.net' id='0002'>
  <body> wherefore art htou Romeo?</body>
  <x target='0000' type='continuation'/>
</message>
Juliet: O Romeo, Romeo! wherefore art htou Romeo?

<message from='juliet@capulet.com/balcony' to='romeo@montague.net' id='0003'>
  <body> wherefore art thou Romeo?</body>
  <x target='0002' type='correction'/>
</message>
Juliet: O Romeo, Romeo! wherefore art thou Romeo?

<message from='juliet@capulet.com/balcony' to='romeo@montague.net' id='0004'>
  <body>Deny thy dad, and refuse thy name;</body>
</message>
Juliet: O Romeo, Romeo! wherefore art thou Romeo?
Juliet: Deny thy dad, and refuse thy name;

<message from='juliet@capulet.com/balcony' to='romeo@montague.net' id='0005'>
  <body>Deny thy father, and refuse thy name</body>
  <x target='0004' type='correction'>
    Adjustment for meter — (Ed)
  </x>
</message>
Juliet: O Romeo, Romeo! wherefore art thou Romeo?
Juliet: Deny thy father, and refuse thy name;

<message from='juliet@capulet.com/balcony' to='romeo@montague.net' id='0006'>
  <body>Or if htou wilt not, be but shorn by love</body>
</message>
Juliet: O Romeo, Romeo! wherefore art thou Romeo?
Juliet: Deny thy father, and refuse thy name;
Juliet: Or if htou wilt not, be but shorn by love

<message from='juliet@capulet.com/balcony' to='romeo@montague.net' id='0007'>
  <body>,
And I'll no longer be a Capulet.</body>
  <x target='0006' type='continuation'/>
</message>
Juliet: O Romeo, Romeo! wherefore art thou Romeo?
Juliet: Deny thy father, and refuse thy name;
Juliet: Or if htou wilt not, be but shorn by love,
And I'll no longer be a Capulet.

<message from='juliet@capulet.com/balcony' to='romeo@montague.net' id='0008'>
  <body>Or if thou wilt not, be but sworn by love</body>
  <x target='0006' type='correction'/>
</message>
Juliet: O Romeo, Romeo! wherefore art thou Romeo?
Juliet: Deny thy father, and refuse thy name;
Juliet: Or if thou wilt not, be but sworn by love,
And I'll no longer be a Capulet.

<message from='romeo@montague.net/orchard' to='juliet@capulet.com' id='rrr1'>
  <body>Shall I hear more, or shall I spak at this?</body>
</message>
Juliet: O Romeo, Romeo! wherefore art thou Romeo?
Juliet: Deny thy father, and refuse thy name;
Juliet: Or if thou wilt not, be but sworn by love,
And I'll no longer be a Capulet.
Romeo: Shall I hear more, or shall I speak at this?

<message from='romeo@montague.net/orchard' to='juliet@capulet.com' id='rrr2'>
  <body>Please ignore that last message.</body>
  <x target='rrr1' type='retraction'>
	Not for your ears, bright angel.
  </x>
</message>
Juliet: O Romeo, Romeo! wherefore art thou Romeo?
Juliet: Deny thy father, and refuse thy name;
Juliet: Or if thou wilt not, be but sworn by love,
And I'll no longer be a Capulet.

S. Implementation Suggestions

S.1 Suggested Message List Implementation

S.1.1 Structure

Message Log
a list of Message Nodes ordered by start timestamp.
Message Node
a list of Correction Stacks ordered by insertion on Continuation directives.
Correction Stack
a list of Messages.

Rendering a message log would generate a series of strings (one for each message node) of the form: [node.last_change] node.sender node.body, ordered by node.start.

Changes to the message log SHOULD cause incremental changes in the output buffer. This would integrate nicely with a dynamic XHTML-IM DOM implementation using 'id' attributes on elements.

Diagram 1: Messages, Correction Stacks, Message Nodes, and the Message Log

+---MessageLog-----------------------------------------------+
|+---MessageNode-----------+ +---MN----+ +-----------------+ |
|| +--CS-+ +--CS-+ +--CS-+ | | +--CS-+ | | +--CS-+ +--CS-+ | |
|| |m0000| |m0001| |m0003| | | |m0005| | | |m0008| |m0007| | | 
|| +-----+ +-----+ |m0002| | | |m0004| | | |m0006| +-----+ | | 
||                 +-----+ | | +-----+ | | +-----+         | |
|+-------------------------+ +---------+ +-----------------+ |
+------------------------------------------------------------+

CS:    Correction Stack
MN:    Message Node
mxxxx: Message with 'id' of "xxxx".

The Message Log in Diagram 1 corresponds to Juliet's messages from the Act 2:Scene 2 example used in the previous section.

Pseudo-code for core objects

class Message {
	DateTime timestamp;
	string id;
	string body;
}

class CorrectionStack {
	Message[] messages;
	DateTime start;	DateTime last_change;
	string body;
	CorrectionStack(Message m) {
		start, last_change, body = m.timestamp, m.timestamp, m.body;
		add m to messages
	}
	Contains(string id) {
		foreach Message m in messages if (m.id == id) return true;
		return false;
	}
	AddMessage(Message m) {
	    if (m.timestamp > this.lastchange) {
			this.lastchange = m.timestamp; this.body = m.body;
		}
		add m to messages
	}
}

class MessageNode : IComparable {
	CorrectionStack[] stacks; // must ensure order of this list is preserved
	MessageNode(Message m) {
		insert new CorrectionStack(m) into parts;
	}
	Contains(string id) {
		foreach CorrectionStack stack in stacks 
			if(stacks.Contains(id))
				return true;
		return false;
	}
	InsertAfter(string id, Message m) {
		locate target_stack that Contains(id)
		insert new CorrectionStack(m) into parts after target_stack
	}
	DateTime start ( get { return parts[0].start; } }
	DateTime last_change { get { return max last_change from stacks; } }
	string body {
		foreach stack in stacks 
			rstring += stack.body; 
		return rstring; 
	}
	int CompareTo(object other) { // order by start
		return this.start.CompareTo(((MessageNode)other).start);
	}
}

Rendering a Message Log

A message log 'log' is a set of message nodes.

foreach node in log.Sort() 
	outputstrings.Add(node.last_change.ToString() + node.sender + node.body);

Correction

log.GetNodeWhichContains(id).GetStackWhichContains(id).AddMessage(m)

Continuation

log.GetNodeWhichContains(id).InsertAfter(id, m)

Retraction

Retraction would be treated as a special case of correction with an empty string as the new message body.

S.7 Suggested User Interface Implementation

These suggestions relate to UI behaviours that would allow the transmitting user to access message update functionality.

S.7.1 Correction

Note: The client should check if the attempted correction is really a continuation (i.e. the update message body starts with the full target message body) and in such cases transmit as a continuation. This will serve to both improve the experience for users with clients not supporting Message Updates and reduce bandwidth requirements.

S.7.2 Continuation

S.7.3 Retraction

Similar mechanism to continuation.


Endnotes