まだかきかけです。提言TMは随時ぼしう。 そのうち大幅に変更になる可能性があります。 http://www.st.rim.or.jp/~mina/italk_log/19981207.italkも参照。
本仕様書は、アイトークのサーバー・クライアント間のプロトコルを規定し、 実装の助けとする。 プロトコルはバージョン0.9と1.0がある。 各バージョンに固有の事項には、[0.9][1.0]の印を付ける。
| ID | 下りデータ | 想定されるクライアントの例 | |
|---|---|---|---|
| ログ | サーバー情報差分 | ||
| null | なし | なし | ログを読まない人工無能 |
| normal | あり | なし | TELNETクライアント、 普通のクライアント、 ログを読む人工無能 |
| biff | なし | あり | ビフクライアント |
| mixed | あり | あり | 高機能クライアント |
アイトークシステムは、一つのサーバーと一つ以上のクライアントから構成される。 クライアントはサーバーにログインし、 両者はプロトコルを用いて会話情報の伝達を行う。 上りの情報は、発言・コマンドなどであり、 下りの情報は、発言・イベント・電報・伝言やアナウンスの再生・ コマンドに対する応答・サーバー情報などである。
サーバー・クライアント間の接続は、 信頼性のある接続指向の通信路を仮定する。
会話の空間はサーバーごとに一つとする。
サーバーは、クライアントを認証しない。 クライアントは、電報においては利用者番号、 伝言・アナウンスにおいてはハンドルにより識別される。 同一ハンドルのクライアントが複数ログインしてもよい。 なお、伝言・アナウンスにおいてサーバーがハンドルを照合する際の規則は実装依存とする。 とくに、英字の大小文字は同一視される場合がある。
特別に設計されたクライアントは、 複数のサーバーに同時にログインすることも可能である。 また、そのようなクライアントがサーバー間でログを中継することにより、 複数サーバーにまたがった会話を実現することも可能である。 しかし、このような利用形態も上記のモデルを逸脱するものではないので、 本仕様では積極的には考慮しない。
本仕様書では、サーバー・クライアント間の通信プロトコルを規定する。 サーバーおよびクライアントの内部の挙動や、 サーバーが利用者に対して送信する可読文の詳細については、 実装依存としてここでは規定しない。
[0.9]プロトコルは、主プロトコル(必須)と副プロトコル(オプション)がある。 どちらも可読文字で構成される行指向のプロトコルである。 TCPを使用する場合、デフォルトのポート番号は、 主プロトコルは12345、副プロトコルはそれより1小さい番号とする。
[1.0]プロトコルは可読文字で構成される行指向のプロトコルである。 TCPを使用する場合、デフォルトのポート番号は12345とする。 0.9の副プロトコルを利用する従来の実装との互換性のため、 1小さいポート番号を同時に使用してもよい。
プロトコルにより通信される情報は下図のように分類される。
┌─ハンドル(ログイン時のみ)
│
┌─上り─┼─発言
│ │
│ └─コマンド
│
│
主プロトコル────┤
│ ┌─発言
│ ┌─ログ─────┤
│ │ └─イベント
│ │
└─下り─┤
│ ┌─電報
│ │
│ ├─裏伝言・アナウンス再生
├─システム出力─┤
│ ├─コマンド応答
│ │
│ └─その他(各種通知など)
│
└─[1.0]サーバー情報差分
┌─上り───切断要求
[0.9]副プロトコル─┤
└─下り───サーバー情報
ここでは、サーバー・クライアント間の情報伝達に使われる文字コード系について規定する。
文字コード系はISO 2022系の文字集合・エンコーディングを基本とする。 上りのコード系は*junet*または*euc-japan*のどちらか、 またはこれらの混合を使用する。 サーバーはシフトJISとの自動判別をしてもよい。 下りのコード系は*euc-japan*([1.0]または*junet*のどちらか)を使用する。
下りの行末コードはCR/LFとする。 [0.9]上りの行末コードは、CR/LFまたはLFとする。 [1.0]上りの行末コードは、CR/LF、CR、LF、またはCR/NULとする。
以上のコード系および行末コードは、 サーバーとクライアントの合意によりセッション中変更することができる。 ISO 10646/Unicodeを使用する場合はUTF-8でエンコードすることが望ましい。
クライアントはTELNETプロトコルに定めるTELNETコマンドコード(0xFFで始まる)を送信してもよい。 受信したサーバーは、文字コードの解釈に先だってTELNETコマンドコードを 解釈あるいは廃棄(ただし0xFF 0xFFは単一の0xFFに変換)しなくてはならない。 このため、TELNETコマンドコードを送らないクライアントも、 文字コードとして0xFFを送る場合は0xFF 0xFFとして送ることが望ましい。 サーバーはクライアントに対してTELNETコマンドコードを送るべきではない。
サーバーとクライアントは、受信した行の中に、 動作に支障をきたすおそれのある文字がある場合、 その文字を適宜変換または廃棄してもよい。
サーバーとクライアントは以下の文字集合をサポートしなければならない。
サーバーとクライアントは、ISO 2022の指示および呼び出しのシーケンスを解釈し、 以下の文字集合をサポートすることが望ましい。
サーバーは以下の私用コードを保存することが望ましい。
サーバーとクライアントは、慣習的に混同あるいは同一視されることの多い文字集合を同一視して扱ってもよい (US-ASCIIとJIS X 0201ローマ文字、JIS C 6226-1978とJIS X 0208-1983/1990/1997など)。
サーバー情報の形式を以下に定義する。空行が入ることがある。
[0.9]サーバー情報の形式は副ブロトコルと利用者一覧コマンド('a'指定時)に共通であるが、 副プロトコルでは対面セクションは省略される。
[1.0]サーバー情報は利用者一覧コマンド('a'指定時)でのみ取得できる。 クライアントタイプがbiffまたはmixedの場合、各行(空行も含む)の先頭に"#! "がつく。
{サーバー情報} ::=
"<italk>" {EOL}
{サーバーセクション}
[ {対面セクション} ]
[ {クライアントセクション}... ]
"</italk>" {EOL}
{サーバーセクション} ::=
"<server>" {EOL}
[ {サーバーセクション行}... ]
"</server>" {EOL}
{対面セクション} ::=
"<you>" {EOL}
{対面セクション行}
"</you>" {EOL}
{クライアントセクション} ::=
"<user>" {EOL}
[ {クライアントセクション行}... ]
"</user>" {EOL}
{サーバーセクション行} ::=
"version=" {サーバー実装バージョン} {EOL} |
"host=" {ホスト名} {EOL} |
"port=" {TCPポート番号} {EOL} |
"users=" {クライアント数} {EOL} |
"boottime=" {time_t型日時} {可読日時} {EOL} |
"currenttime=" {time_t型日時} {可読日時} {EOL} |
"uptime=" {秒数} {EOL} |
"admin=" {管理者名} {EOL} |
"logcode=" {コード系名} {EOL} |
{セクション行}
{対面セクション行} ::=
"userno=" {利用者番号} {EOL} |
{セクション行}
{クライアントセクション行} ::=
"userno=" {利用者番号} {EOL} |
"uptime=" {秒数} {EOL} |
"idle=" {秒数} {EOL} |
"handle=" {ハンドル} {EOL} |
"host=" {ホスト名} {EOL} |
"status=" {ステータス} {EOL} |
"upcode=" {コード系名} {EOL} |
"downcode=" {コード系名} {EOL} |
{セクション行}
{セクション行} ::= {キーワード} '=' {値} {EOL}
仮ログイン(全クライアントタイプ共通)
# Italk Protocol x.x
クライアントタイプnormalの場合
クライアントタイプbiffの場合
クライアントタイプmixedの場合
クライアントタイプnullの場合
上りの最初の行([0.9]ハンドルであるはずのもの)が、 明らかに他の何らかのアプリケーションプロトコルであると認められる場合 (例えばHTTPのGETリクエスト行と認められる場合)には、 サーバーは通信を強制切断するか、当該プロトコルでの通信を試みるなどの対応をとってもよい。
[0.9]上りの最初の行(ハンドルであるはずのもの)がログアウトコマンドの形式に一致する場合、 サーバーはクライアントが接続を取り消したものとみなして切断してもよい。
上りの行の先頭バイトが0x04(コントロールD)である場合、 サーバーはログアウトコマンドと同様に処理してもよい。
ハンドルが空である場合、 サーバーは適当なデフォルトハンドルが入力されたものとみなしてログイン処理をする。
クライアントタイプはセッションの途中で変更することも可能。
ログアウト時、クライアントはサーバーが接続を切断したことを検出してから接続を切断するべきである。
クライアントおよびサーバーは、相手との間に通信障害が発生した場合、 接続を強制切断することができる。 いずれの場合もサーバーは他のクライアントに対してこれをイベントとして通知しなくてはならない。
ログ(発言とイベント)のフォーマットはここでは規定しない。 ただし、先頭の文字は#であってはならない。 サーバー起動イベントは例外的に先頭の文字を#とする。
発言には、発言者のハンドル・発言時刻・発言本文を含む。 イベントには、イベントの内容を示す可読文・イベント発生日時・ イベント発生者ハンドル(もしあれば)を含む。
サーバーは、クライアントからの発言によらず、 組み込みの擬似クライアントの発言を生成して送信してもよい。
サーバー情報以外のシステム出力は下記のいずれかのフォーマットに従う。 いずれも先頭の文字は#である。 サーバー情報は別途規定するフォーマットに従う。
# 可読文
サーバーから利用者への各種の通知を行う。
#形式は、一時的な情報であり、 利用者は読んだあと捨ててもかまわないと考えられる行を示す。
#> 可読文
電報の発信者に対して、 受信者および電報本文をエコーし、 電報を送ったことを通知する。
裏伝言の発信者に対して、 受信者および裏伝言本文をエコーし、 裏伝言を受理したことを通知する。
#< 可読文
電報の受信者に対して、 送信者および電報本文を通知する。
裏伝言の受信者に対して、 裏伝言を再生する(発信者、発信日時および裏伝言本文)。
#>形式と#<形式は、 利用者が電報や裏伝言の送受信状況をログとともに保存したい場合に、 最低限保存する必要のある行を示す。
## 可読文
バックログ先頭・末尾マーカーを示す。
##形式は、マーカーに挟まれたバックログを削除しても、 ログの情報に欠損が生じないようになっていなければならない。
いずれかのクライアントに関して正式ログイン・ログアウト・強制切断・ ステータス設定・ハンドル設定が行われると、 サーバーは、タイプbiffおよびmixedの全クライアント(ログイン・ログアウト・強制切断の場合、そのクライアント自身は除く)に対して、 サーバー情報の差分を以下の形式で提供する。 各行の先頭には"#! "がつく。
{差分} ::= {ログイン情報} | {ハンドル情報} | {ステータス情報} | {ログアウト情報} | {強制切断情報}
{ログイン情報} ::=
"<newuser>" {EOL}
[ {ユーザーセクション行}... ]
"</newuser>" {EOL}
{ハンドル情報} ::=
"newhandle=" {番号} ',' {ハンドル} {EOL}
{ステータス情報} ::=
"newstatus=" {番号} ',' [ {ステータス} ] {EOL}
{ログアウト情報} ::=
"logout=" {番号} {EOL}
{強制切断情報} ::=
"disconnect=" {番号} {EOL}
サーバー情報を利用するクライアントは、 まず利用者一覧コマンド('a'指定)によって全サーバー情報を取得し、 その後サーバー情報差分により随時これを更新する。
ログイン後の上りの行のうち、コマンド文字で始まらないものは発言とみなされる。 空行も発言として有効である。 コマンド文字で始まるものでも発言として扱われる場合がある。
発言に表伝言が含まれる場合、サーバーはこれを適切に処理する。 ただし、サーバーは、特定のハンドルをもつクライアントによる表伝言を無視することができる。 これは、サーバー間でログを中継する人工無能を使用している場合に、 あるサーバーで発せられた表伝言が人工無能によって他のサーバーにばらまかれてしまうのを防ぐ措置である。
クライアントがサーバーに送るコマンドには以下のようなものがある。 サーバーは必須コマンドを実装しなければならない。 サーバーは、実装されていないコマンドあるいは解釈・実行できないコマンドを受理した場合、クライアントに対して#形式でエラーを通知する。
| 名称 | 形式 | サポート | [1.0]正式ログイン前の 使用可否 |
|---|---|---|---|
| ヘルプ | /? | 必須 | 可 |
| 利用者一覧 | /w | 一部必須 | 可 |
| バックログ | /r | 一部必須 | 可(一部不可) |
| ハンドル設定 | /h | 必須 | 可 |
| 電報 | /p | 必須 | 不可 |
| エスケープ | // | 必須 | 可 |
| ログアウト | /q | 必須 | 可 |
| ログアウト | /l | オプション | 可 |
| ステータス設定 | /s | オプション | 不可 |
| 表伝言 | >> | オプション | 不可 |
| 裏伝言 | /m | オプション | 不可 |
| 伝言受取人一覧 | /ml | オプション | 不可 |
| アナウンス | /a | オプション | 不可 |
| アナウンス一覧 | /al | オプション | 不可 |
| [1.0]ネゴシエーション | /x | 必須 | 可 |
コマンドの書式と機能を以下に示す。
{コマンド文字} ::= '/'
{伝言記号} ::= '>' '>' | {代替伝言記号}
{空白} ::= ' ' | TAB | {代替空白文字}
{ハンドル区切り} ::= ',' | {代替ハンドル区切り}
[0.9] {EOL} ::= CR LF | LF
[1.0] {EOL} ::= CR LF | LF | CR | CR NUL
「代替」とあるものは、ロケール依存の文字(2バイト文字など)を使用することを想定したものである。
{ヘルプコマンド} ::= {コマンド文字} '?' {EOL}
使用できるコマンドの一覧と簡単な説明を要求する。 応答は#形式で得られる。書式はサーバーの実装依存である。 サーバー実行中に変化する情報を含めるべきではない。
{利用者一覧コマンド} ::= {コマンド文字} 'w' [ 'a' | 'w' | 'o' ] {EOL}
現在ログインしている全クライアントの情報を要求する。 応答の書式はサーバーの実装依存である。 応答には各クライアントのハンドルと番号を含んでいなければならない。 また、サーバーのホスト名とアクセス手段(TCPにおけるポート番号など)、 各クライアントのログイン元ホスト名とステータスを含めることが望ましい。 クライアントのハンドル・ホスト名・ステータスなどが長い場合には、 サーバーは適宜短縮して出力してもよい('a'指定時を除く)。
'o'と'w'のサポートはオプションである。 'a'と無指定のサポートは必須である。
{バックログコマンド} ::= {コマンド文字} 'r' [ 'a' | 'n' | [ {空白}... ] {行数} ] {EOL}
行数指定時は、ログの最後の指定行数分を要求する。 'a'指定時は、その日の全ログを要求する。 'n'指定時は、前回ログアウト時以降のログを要求する。 どれも指定されていない場合は、サーバーの実装に依存する特定の行数を指定したものとみなす。 バックログの前後には##形式のマーカーがつく。
バックログ送信中にログが増加した場合、サーバーは増加分をバックログ末尾に含めて送信してもよい。 ただし、そのいかんにかかわらず、終了マーカーの後に増加分を送信しなければならない。
サーバーはバックログ送信中にログ以外の情報(他のコマンドへの応答、 到着電報など)を送信してはならない。
'n'のサポートはオプションである。それ以外のサポートは必須である。
[1.0]仮ログイン中は'n'は使用できない。
[0.9] {ハンドル設定コマンド} ::= {コマンド文字} 'h' {ハンドル} {EOL}
[1.0] {ハンドル設定コマンド} ::= {コマンド文字} 'h' {空白} {ハンドル} {EOL}
ハンドルを設定する。ハンドルの前後の空白はサーバーによって削除される。 サーバーは、新ハンドルを設定後、伝言の再生を行う。
[1.0]仮ログイン中にこのコマンドを実行すると、正式ログインする。
[0.9] {電報コマンド} ::= {コマンド文字} 'p' [ {空白}... ] {利用者番号} [ {空白} ] [ {本文} ] {EOL}
[1.0] {電報コマンド} ::= {コマンド文字} 'p' [ {空白}... ] {利用者番号} {空白} [ {本文} ] {EOL}
指定のクライアントに電報を送る。 サーバーは発信者には#>形式で受信者と本文を出力し、 受信者には#<形式で発信者と本文を出力する。 利用者番号0は発信者自身とする。
[0.9]本文がない場合、このコマンドは無視される。 したがって空の電報が送られることはない。 またその際サーバーはエラーを通知しない。
[1.0]本文がない場合、空の電報が送られる。
{エスケープコマンド} ::= {コマンド文字} {コマンド文字} [ {本文} ] {EOL}
コマンド文字で始まる発言をする。
[1.0]仮ログイン中に使用した場合、コマンド文字で始まるハンドルを名乗ったものとみなされる。
{ログアウトコマンド} ::= {コマンド文字} 'q' {EOL} | {コマンド文字} 'l' {EOL}
ログアウトする。 サーバーは他のクライアントに対してログアウトを通知する。
[0.9] {ステータス設定コマンド} ::= {コマンド文字} 's' [ {空白} {ステータス} ] {EOL}
[1.0] {ステータス設定コマンド} ::= {コマンド文字} 's' {空白} [ {ステータス} ] {EOL}
ステータスの設定・変更・取り消しを行う。
{本文} {伝言記号} {ハンドル} [ {ハンドル区切り} {ハンドル} ]... {EOL}
表伝言を送る。各ハンドルの前後の空白はサーバーによって捨てられる。 サーバーは本文を表伝言として蓄積する。 サーバーは本文以降行末までを発言として蓄積・送信する。 さらに、表伝言を受理した旨を発言または#形式で送信してもよい。
これは発言でありコマンドではないが、便宜上ここで解説する。
{裏伝言コマンド} ::= {コマンド文字} 'm' {空白} {本文} {伝言記号} {ハンドル} [ {ハンドル区切り} {ハンドル} ]... {EOL}
裏伝言を送る。各ハンドルの前後の空白はサーバーによって捨てられる。 サーバーは本文を裏伝言として蓄積する。 サーバーは裏伝言を受理したことを示すために本文と受取人を#>形式で送信する。
{伝言コマンド} ::= {コマンド文字} 'm' 'l'
サーバーに蓄積されているすべての伝言の受取人のハンドル一覧を要求する。 応答は#形式で得られる。
[0.9] {アナウンスコマンド} ::= {コマンド文字} 'a' [ {空白} {本文} ] {EOL}
[1.0] {アナウンスコマンド} ::= {コマンド文字} 'a' {空白} [ {本文} ] {EOL}
アナウンスを送るかあるいは取り消す。 アナウンスを送った場合、同名のクライアントが以前送ったアナウンスは上書きされる。
なお、特殊ハンドルallに対する伝言もアナウンスとして処理される。 この場合イベントは送信されない。 また、同名のクライアントが以前送ったアナウンスがあればそれに追加される。
{アナウンス一覧コマンド} ::= {コマンド文字} 'a' 'l' {EOL}
サーバーに蓄積されているすべてのアナウンスを要求する。 応答は#形式で得られる。
{ネゴシエーションコマンド} ::= {コマンド文字} 'x' {空白} {キーワード} '=' {値}
[ ',' {キーワード} '=' {値} ]... {EOL}
クライアントからサーバーに対してネゴシエーションを行う。
| 内容 | キーワード | 値 |
|---|---|---|
| クライアントタイプの宣言 | type | null, normal, biff, mixed |
| 下り文字コードの宣言 | downcode | *junet*など |
| 上り文字コードの宣言 | upcode | *junet*など |
サーバーは以下のタイミングで副プロトコルによるサーバー情報の提供を行う。
サーバー情報は別途規定する形式で送信する。 クライアントが何かデータを送信するとサーバーは接続を切断する。
本プロトコルではセキュリティについては考慮していない。 特に、以下の点に注意。
ここでは、ログ等の推奨フォーマットを解説する。 サーバーの実装の際には、既存のクライアントやツールとの互換性のため、 このフォーマットに従うことが望ましい。 クライアントやツールの実装の際には、このフォーマットを想定してよいが、 可読文の内容に依存することはなるべく避けるべきである。
日時はすべてサーバーのローカル日時である。
(HH:MM:SS)[ハンドル] 発言本文
HH:MM:SSはサーバーが発言を受理した時刻である。 ハンドルは発言したクライアントのハンドルである。
例
(00:00:00)[八重樫] ほげー
# 可読文
可読文にはサーバーの名称・実装バージョン・起動時刻を含む。 このイベント行は例外的に#で始まる。
例:
# italk+ ver. 0.90beta3 [COWBERRY] here @ 1998-01-01(Sun) 00:00:00 JST
([ハンドル@ホスト名] 可読文)
ハンドルはイベントを発生したクライアントのハンドルである。 ホスト名はクライアントのログイン元ホスト名である。 可読文にはイベントの内容とイベント発生時刻を含む。
例:
([八重樫@mech.t.u-tokyo.ac.jp] logged in @ 1998-01-01(Sun) 00:00:00 JST) ([八重樫@mech.t.u-tokyo.ac.jp] logged out @ 1998-01-01(Sun) 00:00:00 JST) ([八重樫@mech.t.u-tokyo.ac.jp] logged out ABNORMALLY @ 1998-01-01(Sun) 00:00:00 JST)
([ハンドル] 可読文)
ハンドルはイベントを発生したクライアントのハンドルである。 可読文にはイベントの内容とイベント発生時刻を含む。
例:
([八重樫] handle change [ハ重樫] @ 1998-01-01(Sun) 00:00:00 JST) ([八重樫] status changed <よー> @ 1998-01-01(Sun) 00:00:00 JST) ([八重樫] status cancelled @ 1998-01-01(Sun) 00:00:00 JST) ([八重樫] announced "よー" @ 1998-01-01(Sun) 00:00:00 JST) ([八重樫] canceled announcement @ 1998-01-01(Sun) 00:00:00 JST)
## __ BACK LOG START _____________________
:
バックログ
:
## -- BACK LOG END ----------------------- 可読文
終了マーカーに可読文がある場合、バックログの行数が含まれる。 行数にはマーカーを含まない。
例:
## __ BACK LOG START _____________________ (00:00:00)[八重樫] ほげー ## -- BACK LOG END ----------------------- (1 lines)
#> 可読文 (利用者番号) [ハンドル] 可読文 #> 電報本文
利用者番号は受信クライアントの番号である。 ハンドルは受信クライアントのハンドルである。 可読文には電報受理時刻を含む。
例:
#> Message to (0001) [Puppet] @ 1998-01-01(Sun) 00:00:00 JST #> /q
#< 可読文 (利用者番号) [ハンドル] 可読文 #< 電報本文
利用者番号は送信クライアントの番号である。 ハンドルは送信クライアントのハンドルである。 可読文には電報受理時刻を含む。
例:
#< Message from (0001) [Puppet] @ 1998-01-01(Sun) 00:00:00 JST #< :P
従来アイトークについては明文化された仕様書がなく、 唯一のサーバーの実装であるitalk+(〜0.8x)の挙動が事実上の仕様であった。 しかし、これでは仕様と実装依存の区別が難しく、 クライアントがサーバーの実装に過度に依存しがちで、 サーバーの仕様変更が制約を受けたりクライアントと齟齬をきたしたりする例があった。 また、サーバー情報のフォーマットのように、 明らかに仕様としての性格をもつ部分についても、厳密な定義が曖昧なままであった。 本仕様書はそのような問題を解消するために編纂された。
仕様の策定にあたっては、以下のような点に留意した。
すなわち1.は記述的仕様、2.は規範的仕様を要求している。 両者は本質的に相容れない性格のものである。 また、プロトコルは最近仕様が大幅に拡張されたが、 現在稼働しているサーバーはほぼすべて旧仕様に基づくものであり、 新旧両方の仕様が必要である。
このような状況をふまえて、 プロトコル仕様も0.9と1.0の2バージョンに分けることにした。 0.9は上記1.の、1.0は上記2.の要求に応えるものである。 ただし、0.9においてitalk+の実装・挙動をことごとく仕様として記述すると、 仕様が肥大化するだけでなくサーバーの実装の自由度を制限するため、 1.0における仕様と実装依存の妥当な切り分けと想定されるものを 0.9においても準用することとした。 実装依存とされた部分のうち、既存のクライアントとの互換性を保つために 明文化しておくことが望ましいものについては、参考規定で触れている。
1.0では0.9から以下のような点が変更されている。
これらの変更にあたっては、0.9との互換性を保ちながら拡張性をもたせることを旨としたが、 副プロトコルの統合など大きく変更された部分もある。
今後新たにサーバー・クライアント・その他ツールなどを実装する場合は、 1.0に適合することを強く推奨する。 また、クライアント(とくにビフクライアント)を実装する場合は、 0.9にも対応することが望ましい。