iChatの文字チャット経由で遠隔地のMacを操作するAppleScriptです。

メッセージの先頭に「sh:」と書けば、その後の文字をシェルコマンドとして、「as:」と書けばその後の文字列をAppleScriptとして実行します。イタズラしようと思えば際限なくイタズラできてしまうので、たいへん危険なAppleScriptであり、取扱いに最大限の注意を必要とします。動作原理を理解できなかったり、シェルコマンドの実行に習熟していないユーザーには使用をすすめません。
Mac OS X 10.5以降、iChatごしに画面共有して遠隔地のMacをコントロールできるようになり、大変便利に活用しています。ただ、そうしたビデオチャットの環境がネットワーク的にできなかったりするケースもあり、それでもリモートコントロールしなければならない、といった事態も考えられます。
そこで、だいたいどこでもつながる文字チャットを使って、shellやAppleScriptのコマンドを送り、文字チャット経由で結果を確認することができるプログラムを(ちょろっと)書いてみました。とりあえず、2台のMacを並べてiChat経由でリモート操作できています。
まずは、動作原理の説明から。

iChatは、幾多のバージョンアップを経て、さまざまなアプリケーション内部のイベント(ビデオチャットを仕掛けられたとか、テキストチャットを受信したとか)に応じて、音を鳴らしたり、Dockのアイコンをジャンプさせたり、Text To Speechを利用して文字を読み上げることができるようになっています。この設定は、iChatの「環境設定」の、「警告」で行うことができます。

それらの一環としてAppleScriptを呼び出すことができるようになっています。OS標準では、各種チャットを自動受付するAppleScriptなどが用意されており、これらは/Library/Scripts/iChat/に入っています。プログラムの書き方は、それらのサンプルを読めばだいたい分るようになっています。
問題は、iChat内で実行を指定するAppleScriptは、普通のスクリプトとして保存すると実行できないという点です。明示的にAppleScriptエディタ上で「テキスト」として保存して使用しなければなりません。
本Scriptでは、テキストチャットで話しかけられたときのイベント「メッセージを受信」と、テキストチャット中にメッセージを受信したときのイベント「チャットルームで受信したメッセージ」で、このAppleScript(テキスト形式で保存)を指定する必要があります。
本AppleScriptを仕掛けたマシンに、インターネット経由でiChatの文字チャットを開始し、冒頭で紹介したとおり、「sh:」とか「as:」といった文字で始まるメッセージを送信すると、それぞれシェルコマンドやAppleScriptとして評価・実行が行われます。asコマンドを送る際に、「application」を「app」などと略すことも可能です。
もう少し改良して、チャット経由でAppleScriptファイルを送りつけると、実行結果を文字チャットで返してくるとかいったところまでやってみたいです。また、シェルの実行に関してもdo shell scriptコマンドではなくTerminal.appで実行するようにすれば、ワンショットの一発コマンドやり逃げではなく、もう少し実用性が出てくるのではないかと考えます。

▲shellコマンドでコントロール

▲AppleScriptでコントロール
プログラム的には、ぜんぜん大したことをやっていないのですが、iChatで実行するAppleScriptの注意点がひとつ。プログラムを修正したら再度iChatの環境設定でScriptを指定し直す必要があります。元のプログラムを直しても、指定し直さないとiChat側に変更が通知されないようになっています。
つまり、これをやらないと、修正前のScriptが実行され続けてしまうことになります。そのため、不具合修正がちょっとやりづらい、といったところでしょうか。iChatからのイベントを受信する部分は最低限の記述にしておき、処理本体は外部のアプレット(AppleScriptアプリケーション。常時起動タイプ)で行うとよいかもしれません。
実際に使ってみて……シェルコマンドの実行結果が複数行にわたってしまうと(psコマンドの実行結果とか)、1行目以外は結果が返ってきませんね。やはり、複数行になってしまう場合には結果をテキストファイルに書き出して、iChatのファイル転送機能を使って送ってくるようにしたいところです。ただ……こんな特殊用途のどーーでもいい使い捨てプログラムに、そんなに入れ込んでもしょうがないような、、、、
| スクリプト名:iChat_mes_test.applescript |
using terms from application “iChat” – 最初にテキストチャットで話しかけられた場合の対応(「メッセージを受信」で指定) on received text invitation theMessage from theBuddy for theChat accept theChat send “Welcome to shell/AppleScript Remote Control. “ end received text invitation – チャットが成立した後のメッセージ受信(「チャットルームで受信したメッセージ」で指定) on message received theMessage from theBuddy for theChat set aRes to “” –set theResponse to “ぴよ〜” & theMessage if (theMessage begins with “as:”) or (theMessage begins with “sh:”) then set aRes to execCommand(theMessage) of me end if if aRes is not equal to “” then send aRes to theChat end if end message received on execCommand(aText) if aText begins with “as:” then set bText to text 4 thru -1 of aText try set aRes to run script bText set aClass to class of aRes if aClass = list then set aRes to listToText(aRes) of me else if aClass = record then set aRes to recordToText(aRes) of me else set aRes to aRes as string end if return aRes on error aMes return aMes end try else if aText begins with “sh:” then set bText to text 4 thru -1 of aText try return (do shell script bText) on error aMes return aMes end try end if end execCommand on listToText(aList) set listText to {“{”} set quotChar to ASCII character 34 set firstFlag to true repeat with i in aList set j to contents of i set aClass to class of i if (aClass = integer) or (aClass = number) or (aClass = real) then set the end of listText to (getFirst(firstFlag) of me & j as text) set firstFlag to false else if (aClass = string) or (aClass = text) or (aClass = Unicode text) then set the end of listText to ((getFirst(firstFlag) of me & quotChar & j as text) & quotChar) set firstFlag to false else if aClass is list then set the end of listText to (getFirst(firstFlag) of me & listToText(j)) –ちょっと再帰処理 set firstFlag to false else if aClass is record then set the end of listText to (getFirst(firstFlag) of me & recordToText(j)) set firstFlag to false end if end repeat set the end of listText to “}” set listText to listText as text return listText end listToText on getFirst(aFlag) if aFlag = true then return “” if aFlag = false then return “,” end getFirst on recordToText(aRec) try set a to aRec as string on error aMsg set a to aMsg end try set b to repChar(a, “のタイプを string に変換できません。”, “”) return b end recordToText –文字置換ルーチン on repChar(origText, targStr, repStr) set {txdl, AppleScript’s text item delimiters} to {AppleScript’s text item delimiters, targStr} set temp to text items of origText set AppleScript’s text item delimiters to repStr set res to temp as text set AppleScript’s text item delimiters to txdl return res end repChar end using terms from |
|
▼新規書類に ▼カーソル位置に ▼ドキュメント末尾に
|