importer.txt (Documentation for XJMail importer module) Document ver. 03 (2002年12月) Copyright 2000-2002 ktkawabe, all rights reserved. このテキストは、独自に XJMailの importerモジュールを開発したい 方のためのものです。個々の importer の使用法、インストール法等 につきましては、それらの importer に付属するドキュメントをお読 み下さい。 --------------------------------------------------------------- 1: XJMailのimporterとは 2: XJMailのファイル形式 3: Importer API 3-1: 使用言語とエントリポイント 3-2: モジュールのファイル名とパス 3-3: プロシジャ名、変数名 3-4: モジュール内から使用できるXJMailのプロシジャ、変数 3-4-1: 役に立つかもしれないグローバル変数 (完備ではありません) 3-4-2: 役に立つかもしれない PROC (完備ではありません) 3-4-2-1: XJMailの動作に影響を与えないPROC 3-4-2-1-1: ファイル操作関連 3-4-2-1-2: メイルファイル名の生成/検索等 3-4-2-1-3: プログラムの素性 3-4-2-1-4: バッファ操作関連 3-4-2-1-5: ユーザへの通知 3-4-2-2: XJMailの動作に影響を与えるPROC 3-4-2-2-1: フォルダ移動 3-4-2-2-2: インデックス管理 3-4-2-2-3: メイルダウンロード/作成/送信等 3-4-2-2-4: ファイルコピー/移動/削除/マーク等 3-5: エラー処理 3-6: ソースコード例 4: モジュールの配布 5: 参考文献 --------------------------------------------------------------- 1: XJMailのimporterとは XJMail の importer とは、EPOC で稼働する email client である XJMail において、他のメイラから XJMail が使用する形式にメイル を変換するためのモジュールです。 (が、他の目的に使用する事も出来ます。) 2: XJMailのファイル形式 XJMail のメイル形式は、2002年12月16日現在、以下の様になってい ます。 ・一つのメイルが一つのファイルに変換されます。 ・ヘッダ: ヘッダの日本語部分は、SJISに変換されます。 その他の部分は変換されません。 ・ボディ: charset=ISO-2022-JP で Content-Transfer-Encoding=7bit の部分、もしくはMIMEを使わないローカライズされたRFC822のメイル の本文については、SJISに変換されます。その他の部分は変換されま せん。 ・日本語に関連しない部分は、何ら変換されません。例外として、原稿 系のフォルダ (out と draft) の中では、ヘッダとボディの区切りが 空行ではなくて "----"と復帰改行になっております。 3: Importer API 特定のメイラのメイルを XJMail 形式に変換したい場合、ユーザーが 自分で Importer を書く事が出来ます。Importer の動作に関しては、 特に制限を設けません。 ただし、以下の点に注意して下さい。 3-1: 使用言語とエントリポイント ImporterはOPLモジュールで、XJMailの中から呼び出されます。 Importerのエントリポイントとして、 Import: というプロシジャを設けて下さい。このプロシジャの中で、何でもや りたい事をやって下さい。 3-2: モジュールのファイル名とパス XJMailはImporterのファイル名をそのままユーザーに提示します。 ファイル名は必ず.opoという拡張子を持たせて下さい。 その上で、分かりやすいファイル名をつけて下さい。 Importerモジュールは \System\Apps\XJMail\Importer というフォルダに入れるようにして下さい。 XJMailは、使用出来るImporterを自動的にサーチします。 3-3: プロシジャ名、変数名、初期化ファイル等 Importer 内部で新たに定義するプロシジャと変数の宣言には、以下 の制限をつけるものとします。 ・XJMail 本体の中に存在するプロシジャと同じプロシジャ名を新たに 宣言しない。 ・XJMail 本体の中で使用されているグローバル変数と同じ名前のグロー バル変数もしくはローカル変数を宣言しない。 また、Importer固有のキーワードをXJMail本体が使用する初期化ファ イルに書き込んではいけないものとします。必要なら importer が存 在するフォルダの中に importer と同名で拡張子が ".ini" 等の初期 化ファイルを作成してください。 3-4: モジュール内から使用できるXJMailのプロシジャ、変数 モジュール内から、XJMailのプロシジャやグローバル変数を使用する ことが可能です。 3-4-1: 役に立つかもしれないグローバル変数 (完備ではありません) 一般論として、GLOBAL 変数を使用する際には、使用する PROC 内で その GLOBAL 変数を EXTERNAL 宣言すべきです。 (更に言えば モジュール先頭で DECLARE EXTERNAL を宣言しておくと もっと良いでしょう。) そうでないと、ランタイム時に Undefined Externals エラーが出る等、 予期しないバグが混入しがちになります (文献 [1][2])。 以下に、役に立つかもしれない主要なグローバル変数のリストを示し ます。完全なリストが欲しい場合、ソースの中の PROC main: 内の GLOBAL宣言を見れば判るはずです。 予期できないバグの混入を防ぐため、XJMailのある特定のグローバル 変数の値を変えるのは、その変数の役割を完全に把握してからにした 方が無難です。 ---------------------------------------------------------------- rootfolder$ : 現在のユーザーアカウントにおける、メイルフォルダ 最上部のパス currentfolder$: 現在ユーザーが「居る」フォルダ xjmailpath$ : XJMail.APPのフルパス accountname$ : 現在のアカウント名 editor$ : エディタ名 ex_viewer$ : 外部ビューアを指定する場合のビューア名 POPhost$ : POPサーバー名、もしくはIPアドレス POPuser$ : POPユーザー名 SMTPhost$ : SMTPサーバー名、もしくはIPアドレス SMTPFrom$ : メイル送信の際、From: に入れる文字列 signature$ : シグネチャを入れる設定になっている場合、そのファ イル名 signature% : 非ゼロ(原則として1) の場合シグネチャを入れる mailnum& : 現在のフォルダ内に存在するメイル数 indexbuf& : 現在のフォルダのインデックス indexsize& : 上記インデックスのサイズ idx_table& : インデックスの各行のオフセットを格納するテーブル。 i&行目 (0<=i&0): 指定されたキーワードのうち、n個は見つからなかった ちなみに iniFile$中に keyword-querymではじまる行が存在しない場 合、value-querym には空文字列が入る。 数値等も全て文字列として扱われる事に注意。詳細な用法は、例えば SMTPSettingReader%:(iniFile$) を参照せよ。 例) c:\test.iniの内容が以下のようであったとする。 MYNAME=ktkawabe@hoo.bar LASTUSED=2001/02/25 HOO=hoo.bar test.ini の中に  "HOO=" と "BAR=" ではじまる行があるかどう か調べたい場合のコードは以下のとおり: LOCAL nkey%, keyword&, answer&, hoo$(255), bar$(255) nkey%=2 : keyword&=ALLOC(nkey%) : answer&=ALLOC(nkey%) POKE$ keyword&, "HOO" POKE$ keyword&+256, "BAR" iniReader%("c:\test.ini", nkey%, keyword&, answer&) hoo$=PEEK$(answer&) bar$=PEEK$(answer&+256) FREEALLOC keyword& FREEALLOC answer& この結果、hoo$ には "hoo.bar" が、bar$ には空文字列が代入さ れる。 IniWriter%:(iniFile$, nkey%, keyword&, answer&) iniFile$ に対して、特定のキーワードとその値を書き込む。 テキストで記述された初期化ファイル操作のコア部分。XJMailでは、 アカウントファイルの内容を更新するため等に、SMTPSettingWriter: etc.の中から使用されている (モジュール毎の設定ファイルを更新す るのに役立つでしょう)。 iniFile$、keyword& 及び answer& の書式については IniReader%: を参照せよ。IniWriter: を使用する場合、answer& には自分でvalue を書き込まねばならない。 ファイル内に存在しない keyword については新たな行が加えられ、 既に存在する keyword については value が書き換えられる。 ファイルが存在しない場合には新たにファイルが作成された上で内容 が書き込まれる。 数値等も全て文字列として扱われる事に注意。詳細な用法は、例えば SMTPSettingWriter:(iniFile$) を参照せよ。 WriteAllocatedBuffer%:(file$, buffer&, length&) file$というファイルに buffer&ではじまる length&バイト分の内容 を書き込む。 file$が既に存在する場合は上書きされてしまうので注意。 3-4-2-1-2: メイルファイル名の生成/検索等 NextFile$:(spec$) 注) この PROC は現在のXJMailでは使用されていないが、Importer の互換性確保のために残されている。 XJMailでは、一つのメイルが一ファイルに対応し、ファイル名は4桁 の10進正数で表される。 NextFile$:(spec$) は、spec$+"????" (????は4桁10進正数) という ファイル名を持つ全てのファイルの中で、????の部分が最大のものを 検索し、????+1に相当する 4桁10進正数の文字列を返す。 既に spec$+"9999"が存在すれば、空文字列を返す。 spec$+"????"に相当するファイルが存在しなければ、"0001"を返す。 任意のフォルダにメイルファイルを追加する際、ファイル名を決定す るために使用する事が出来る。 spec$には任意の文字列を指定出来る。例えば spec$="c:\tmp\tmp"と すれば、c:\tmp\tmp???? という形式のファイル名が検索される。 FirstFile$:(spec$) 注) この PROC は現在のXJMailでは使用されていないが、 Importer の互換性確保のために残されている。 spec$+"????" (????は4桁10進正数) というファイル名を持つファイ ルの中で、???? が最も小さいものを探し、"????" 部分を文字列とし て返す。 マッチするものが無ければ空文字列を返す。 CountFiles&:(spec$) spec$+"????" (????は4桁10進正数) というファイル名にマッチする ファイルの数を返す。 GEN2$:(x&, maxlen%) XJMailでは、メイルのファイル名を生成するのに使用されている。 整数x&を maxlen%桁で右揃えし、左側に "0"を付加。 例) GEN2$:(920, 5) は "00920" です。 Is4Digit&:(name$) name$が4桁の10進数であれば1を返し、そうでなければ0。 3-4-2-1-3: プログラムの素性 IsOPL%:(AppSpec$) AppSpec$であらわされるプログラムが C++ APPなら 0 OPL APPなら 1 OPO なら 2 不明なら -1 を返す。 OPO であるかどうかの判定はさぼっており、AppSpec$が "\"を含めば 全て OPO という事にしてしまっている。 本物のAppの場合にはパスを含めずに名前だけを (例えば "XJMail") 渡すこと。 3-4-2-1-4: バッファ操作関連 CountLines&:(buffer&, buflen&) buffer&からはじまるbuflen&バイトの領域の中に、復帰改行(CR/LFの ペア)が何回出てくるか数えるだけのもの。 最終行に復帰改行が伴わない場合、その行は数えられない。 CommentOutBuffer&:(bufferaddr&, buflen&, comment$) バッファの中のbuflen&バイト目までの全ての行頭に comment$を付加 する。 XJMailではReply時の引用部作成に使用。 bufferddr&はバッファ変数ではなくて、バッファ変数へのポインタ ADDR(buffer&)。 このPROCは必要に応じてバッファの伸張を行い、comment$付加後の バッファサイズを返す。 伸張に失敗した場合、"Not enough memory" ダイアログを表示した後 に負数を返す。 3-4-2-1-5: 文字列操作関連 PadFromLeft$:(string$, pad$, maxlen%) string$ が maxlen% に満たない場合、右揃えして左側を pad$の最初 の一文字で埋める。 3-4-2-1-6: ユーザーへの通知 escape_dialog:(message$) 単に message$というタイトルで "OK"ボタンが一つだけあるダイアロ グを表示。 LaunchHelp: 設定に従い XJMailのヘルプを立ち上げる。 AboutDialog: AboutDialogを表示。 3-4-2-2: XJMailの動作に影響を与える PROC とりあえずそこそこ安全そうなものだけ記載しておきます。 ---------------------------------------------------------------- フォルダ移動 ChangeFolder:(folder$, msg&) インデックス管理 AddToIndex:(stc&, srclen&, folder$, file$) メイルダウンロード/作成/送信等 CmdR%: -> Remote Mailboxへの接続やダウンロードなど CmdN%: -> 新規メイル作成 CmdSR%: -> Reply原稿作成 SendThisMsg:(msg&) ファイルコピー/移動/削除/マーク等 MoveMessages:(flag%) CmdSM%: -> MoveMessages:(1)と等価 DeleteMessages:(nonstop%) MarkAll:(type&) IsThisLineMarked%:(msg&) リストビュー操作 LV_MvDn&: -> カーソルを一つ下に。 LV_MvUp&: -> カーソルを一つ上に。 LV_Scrl:(lines&) -> lines&行スクロール。 LV_SetCurrent:(num&) -> num&番目のメイルを選択状態にする。 ---------------------------------------------------------------- 3-4-2-2-1: フォルダ移動 ChangeFolder:(folder$, msg&) folder$に移動し、msg&にカーソルを合わせる (先頭msg&は0)。 もしこのフォルダの内容とインデックスの内容に不一致がある場合、 インデクスの更新を行う。 msg&=-1: とにかく最後のメッセージにカーソルを合わせる(大体い つも安全)。 msg&=-2: XJMail では Move/Delete messages の中から使用されて いるが、この二つの操作の動作を完全に理解しているので なければ使わない事。 3-4-2-2-2: インデックス管理 AddToIndex:(src&, srclen&, folder$, file$) エンジン部だが、解って使う分には安全。 folder$内の index.jm5という名前のインデクスファイルに、新たに つけ加えたいメイルのヘッダ情報を登録する。 メイルの内容はsrc&というバッファに入れて渡す (srclen&バイト分)。 この PROC を呼ぶ前に、src& からはじまるバッファの内容が正しい RFC822/2822 形式になっているかどうか確認するべき。 file$ は登録されるファイル名で、4桁10進正数。このファイル名が XJMail的に正しいかどうか、folder$内の他のファイルとかぶってい ないかどうかについてのチェックは行われない。 この PROC は純粋にインデクスファイルをいじるだけで、ファイルの 生成とか移動は全く行わない。ファイル実体の操作については呼び出 し側で処理すべき。 currentfolder$以外のフォルダにファイルを登録するのであればそこ そこ安全。 currentfolder$にファイルを登録する場合、直後に ChangeFolder:() する事。 3-4-2-2-3: メイルダウンロード/作成/送信等 CmdR%: 完全にUI。 Remote Mailboxへの接続、ダウンロード、メイルのデコード、inbox への登録、ダウンロードされたメイルがあれば inbox に移動、等の 処理を行う。大体いつでも安全。 CmdN%: 完全にUI。 新規メイルテンプレート作成後、エディタに渡してユーザーに提示。 ユーザーが書き終わったら、そのまま送るか、draft または Out へ の移動と登録の処理を行う。 大体いつでも安全。 CmdSR%: 完全にUI。 Reply原稿作成。現在カーソルがあるメイルの内容から Reply原稿を 作成し、エディタに渡してユーザーに提示。以後は CmdN%: と同じ。 SendThisMsg:(msg&) 現在のフォルダが draftまたはoutの場合にのみ使う事。 フォルダ内のmsg&番目のメイルを送信し、必要な処理を行う。 POP_before_SMTP が指定されている場合には、送信前に「認証のみ」 の POP 接続が行われる。 msg& が存在する事のチェックは行われないので注意。 先頭原稿の msg& はゼロ。 3-4-2-2-4: ファイルコピー/移動/削除/マーク等 MoveMessages:(flag%) flag%が 0ならコピー、そうでなければ移動後に、インデクスの処理 を行う。 現在のフォルダ内にマークのついたメイルがあれば、それをコピー もしくは移動。 マークが一つも無い場合、カーソルのあるメイルをコピーもしくは 移動。 CmdSM%: -> MoveMessages:(1)と等価 DeleteMessages:(nonstop%) メイルの削除。 現在のフォルダ内にマークのついたメイルがあれば、それを削除。 マークが一つも無い場合、カーソルのあるメイルを削除。 その後に、インデクスの処理を行う。 nonstop% が非ゼロの場合、削除の可否の確認をしない。 MarkAll:(type&) type&が -1の場合、状況により次の動作をする: 現在のフォルダ内の全てのメイルが既にマークされていれば、全て のマークを取り除く。 一つでもマークされていないものがあれば、全てのメイルにマーク をつける。 type&が 0の場合、状況によらず全てのマークを取り除く。 type&>0の場合、状況によらず全てのメイルに type&をキャラクタコー ドとする文字でマークする。 通常は type&は (0,-1,%*) のうちのどれかに設定すべき。 IsThisLineMarked%:(msg&) 現在のフォルダの msg& 番目のメイルにマークがついているかどうか 判定。msg&はゼロから始まる事に注意。 3-4-2-2-5: リストビュー操作 LV_MvDn&: 完全なUIであり、安全。 カーソルを一つ下に移動し、必要に応じ、ビューのスクロールを行う。 移動出来た場合は 0を、移動出来ない (既に一番下のメイルにカーソ ルがある) 場合には -1を返す。 LV_MvUp&: 完全なUIであり、安全。 カーソルを一つ上に移動し、必要に応じ、ビューのスクロールを行う。 移動出来た場合は 0を、移動出来ない (既に一番上のメイルにカーソ ルがある)場合には -1を返す。 LV_Scrl:(lines&) lines&行スクロールする。正値は下方向への移動、負値は上方向。 この PROC はカーソル行について全く注意を払わないので、 LV_SetCurrent と組にして使うべき。 lines& としてとんでもない値を指定した場合、値によって最初のメ イルもしくは最後のメイルまでスクロールが行われる。 LV_SetCurrent:(num&) 識別番号 num& のメイルの上にカーソルを合わせる。num& が画面上 に無い場合の動作は保証されない。 これ以上の情報につきましては、ER3MSGSUITEのソースを御覧になって 下さい。 3-5: エラー処理 インポーター内部のエラーについては、ONERR 等を使用して、極力 インポーターモジュール側で処理するべきです。 XJMail 1.31 かそれ以後のバージョンでは、モジュール側の PROC Import: を ONERR で保護していますが、エラーが起きた場合には ユーザーに細かい情報を提示することは出来ません。 なるべくモジュール側で細かいエラー情報を表示する様にして下さ い。 3-6: ソースコード例 独自のインポータを開発する際のテンプレートとして使える様に、 インポーターのソースコードを用意しました。 importer_example がそれですので、適当に使いまわして下さい。 4: モジュールの配布 有用なモジュールを作成なさった場合、もちろん御自分で配布なさって 下さって構わないのですが、その際、配布パッケージに本文書を含めて 下さると嬉しいです。 また、もしよろしければ是非ktkawabeまで御連絡下さると、更に嬉しい です。ktkawabeのwebサイトからリンクさせていただきたいと思います。 なお、蛇足になりますが一応注意させていただきます。 モジュール内部からXJMailのプロシジャなりグローバル変数なりを使用 している場合にも、モジュールのソースにXJMailのソースが入っている ので無ければ、そのモジュールの配布にあたって XJMail利用許諾書 (XJM_COPY.TXT) に従う必要は全くありません。 5: 参考文献 [1] OPL User Guide (Psion Computers PLC, 1997) "Basic"章、 "Calling Procedures"節の "`Undefined Externals' Error"と "Series 5 Header Files, Constants and Procedure Prototypes" [2] OPL SDKドキュメント "EPOC OPL Guide & Reference"-> "Programming in OPL" -> "OPL Basics"の "Calling Procedures"-> "`Undefined Externals' Error"と "Including Header Files"-> "Procedure Prototypes" --------------------------------------------------------------- ktkawabe (ktkawabe@hi-ho.ne.jp)