Archive for the 'iChat/Messages' Category

2016/04/27 AppleScriptから電話にアクセスする

指定番号に電話をかけたり、指定番号にSMSのメッセージを投げるAppleScriptです。

OS X 10.10, Yosemiteから、MacとiPhoneをひもづけておくとMacで電話を受けたり、Macから電話をかけたりできるようになりました。

→ OS X Yosemite: Mac を使って電話を受ける/かける

この設定が済んでいれば、以下のような簡単なAppleScriptを実行するだけで、電話がかけられます。ノーティフィケーション・ダイアログが表示されるため、「発信」ボタンをクリックすれば(このあたり、GUI Scriptingでクリックできそう)、電話が発信されます。

プログラム中の「tel://」以下の部分に実際の電話番号を入れておけばかけられます(カッコ、ハイフンなどは入れず、数字のみ)。

phonecall.png

AppleScript名:電話番号を呼び出す
open location “tel://03XXXXXXXX”

★Click Here to Open This Script 

同様に、携帯電話のSMSサービス経由でメッセージを送ることもできます。以下のプログラムのbuddyのあとに電話番号を入れておくとメッセージ送信できます(カッコ、ハイフンなどは入れず、数字のみ)。

以前は、SMS Macという有償のアプリケーションを使う必要があったのですが、OS標準でこの機能がサポートされていることに驚かされました。

iCloud経由のメール送信は1日に200件までという上限が設定されており、このSMS経由のメッセージ送信にも同様の上限値が設定されている可能性があります。

→ iCloud におけるメールボックスの容量およびメッセージの送信制限

img_3554.jpg

img_3556.jpg
▲ためしにAppleScriptから3秒間隔で210回SMS送信実験してみましたが、200回目で止まるようなことはありませんでした

→ キャリア(ソフトバンク)側で、SMSを200通/日以上送信した場合に、その後24時間送信規制を行うとのこと。明日はSMS送信が行えない模様

AppleScript名:携帯電話にSMS経由でメッセージを送信する
tell application “Messages”
  set target to buddy “080XXXXXXXX” of service “SMS”
  
send “SMS sent via AppleScript” to target
end tell

★Click Here to Open This Script 

2010/07/03 iChatで文字チャットの相手に文字列を送信。長い場合にはテキストに書き出してzip圧縮して送信

iChatで文字チャットの相手に文字列を送信。長い場合にはテキストファイルに書き出してzip圧縮してそのファイルを送信するAppleScriptです。

iChat経由で何らかのコマンドのやりとりを行うような場合に、コマンドの実行結果が長い(実際に調査してみたら2419文字以上)場合にはiChatが送信をブロックするので、メッセージの送信が行えません。

そこで、2419文字以上の結果をiChat経由で送信する場合には、結果をテキストファイルに書き出してzip圧縮し、zipファイルを送り返すようにしてみました。

これなら、結果が長くなるような場合でも問題なく返信することができます。

iChatでメッセージの文字列を相手に送るのも、ファイルを相手に送るのも同じsendコマンドで行えます。

スクリプト名:iChatで文字チャットの相手に文字列を送信。長い場合にはzip圧縮して送信
–すでに文字チャットを開始していることが前提条件
set aPerson to getPersonOfChat1() of me

set aRes to do shell script “cd ~/usr/bin && ls -la” –ちょっとテスト用に長めの文字列を作ってみた

set aLen to length of aRes

if aLen > 2419 then –iChatの文字チャットで送信できる文字の最大数を確認したら、2419文字だった(Mac OS X 10.6)
  set aRes to makeZipFile(aRes) of me –メッセージ内容をテキストファイルに書き出してZip圧縮
  
set aRes to POSIX file aRes
end if

tell application “iChat”
  tell chat 1
    send aRes to aPerson –メッセージ(文字)もファイルも送信コマンドは同じ
  end tell
end tell

–Chat 1の相手を取得する
on getPersonOfChat1()
  tell application “iChat”
    tell chat 1
      set aPerson to participants
      
set aPerson to first item of aPerson
      
return aPerson
    end tell
  end tell
end getPersonOfChat1

–指定データをファイルに書き出してzip圧縮
on makeZipFile(aStr)
  set aPath to (path to temporary items from system domain) as string
  
set afN to (do shell script “uuidgen”) & “.txt”
  
  
set aFullPath to aPath & afN
  
write_to_file(aStr, aFullPath, false) of me
  
  
set f1Path to quoted form of POSIX path of aFullPath
  
set f2Path to quoted form of POSIX path of (aFullPath & “.zip”)
  
  
try
    with timeout of 3600 seconds
      set aRes to do shell script “zip -r -j “ & f2Path & ” “ & f1Path
    end timeout
  on error
    return false
  end try
  
  
return (POSIX path of (aFullPath & “.zip”))
end makeZipFile

–ファイルの追記ルーチン「write_to_file」
–追記データ、追記対象ファイル、boolean(trueで追記)
on write_to_file(this_data, target_file, append_data)
  try
    set the target_file to the target_file as text
    
set the open_target_file to open for access file target_file with write permission
    
if append_data is false then set eof of the open_target_file to 0
    
write this_data to the open_target_file starting at eof
    
close access the open_target_file
    
return true
  on error error_message
    try
      close access file target_file
    end try
    
return error_message
  end try
end write_to_file

▼新規書類に ▼カーソル位置に ▼ドキュメント末尾に

2010/06/19 iChat経由で受信したAppleScriptファイルを実行

iChat経由で受信したAppleScriptファイルをAppleScriptエディタ上で実行し、結果をiChatで返すAppleScriptです。

離れた場所にあるマシン用にAppleScriptを作成し、自分の手元では動いていたのに、相手のマシン上で動かなかったりエラーが発生した……というケースに対応すべく、先日シェルコマンドやAppleScreiptコマンドをiChat経由で受信して実行するAppleScriptを作成しましたが……やはり、まとまった処理を実行させたいケースが多く、ちょっとしたコマンドを実行するだけでは満足できません。

そこで、iChat経由でAppleScriptファイルを受信したら実行して結果を返すAppleScriptを作成した次第です。

本AppleScriptは、かならずテキスト形式で保存して、iChatの環境設定>「警告」で「ファイル転送の受信」および「ファイル転送の完了」イベントで本Scriptを実行するよう設定する必要があります。

ic10.jpg

マシンAの上のiChatにこのScriptを設定。マシンB上からiChatでマシンAにチャットを仕掛け……マシンBからiChatウィンドウにAppleScriptファイルをドラッグ&ドロップすると……マシンB側で送信されたAppleScriptを実行し、結果をマシンBに返します。

まだテスト段階のプログラムなので、デスクトップ上に受信したファイル転送のプロパティをログとして書き出します。

ここまで作成できたので、元のプログラムと合体させれば、リモートメンテナンス用のツールとして割と実用性が出てくるのではないでしょうか。

スクリプト名:ichat_file_receive_2.applescript
using terms from application “iChat”
  
  
on received file transfer invitation theFileTransfer
    accept theFileTransfer
  end received file transfer invitation
  
  
on completed file transfer theFileTransfer
    
    
set aProp to properties of theFileTransfer
    
    
–ログに記録
    
set dtPath to path to desktop as string
    
set wFilePath to dtPath & (do shell script “date +%Y%m%d-%H%M%S”)
    
write_to_file_asRec(aProp, wFilePath, false) of me
    
    
set aFile to (file of theFileTransfer) –ファイル
    
set aStatus to transfer status of theFileTransfer –転送状態
    
set aDirection to direction of theFileTransfer –転送方向
    
set sentBuddy to buddy of theFileTransfer –転送してきたBuddy
    
    
if aDirection is not equal to incoming then return –ファイル転送が「受信モード」でなければリターン
    
if aStatus is not equal to finished then return –ファイル転送が終了していなければリターン
    
    
–指定ファイルがAppleScriptかどうかをチェック
    
set aProp to info for (aFile as alias)
    
if kind of aProp = “スクリプト” and file type of aProp = “osas” then
      set {aRes, aReason} to executeAS(aFile) of me
    end if
    
    
if aRes = false then
      send aReason to sentBuddy
    else
      –通常の結果返信
      
send aReason to sentBuddy
    end if
    
  end completed file transfer
  
  
end using terms from

–指定のaliasのAppleScriptをオープンして結果を返す
on executeAS(asFileAlias)
  tell application “AppleScript Editor”
    try
      open asFileAlias
    on error erMes
      return {false, “AppleScriptファイルのオープンに失敗しました。” & erMes}
    end try
    
    
tell window 1
      set bDoc to name
    end tell
    
    
tell document bDoc
      
      
–実行する
      
try
        execute
      on error erMes
        –エラー発生時にはクローズしてfalseを返す
        
close without saving
        
return {false, “AppleScriptファイルの実行時にエラーが発生しました。” & erMes}
      end try
      
    end tell
    
    
–GUI Scripting経由でAppleScriptの実行結果を取得する
    
activate application “AppleScript Editor”
    
tell application “System Events”
      tell process “AppleScript エディタ” –各国語環境で名前は違うかもしれない、と日本語で書いてみる
        keystroke “3″ using {command down} –command-3 結果を表示
        
set resVal to value of text area 1 of scroll area 1 of group 1 of group 1 of splitter group 1 of window 1
      end tell
    end tell
    
    
tell application “AppleScript Editor”
      tell document bDoc
        close without saving
      end tell
    end tell
    
    
return {true, resVal}
    
  end tell
  
end executeAS

–ファイルの追記ルーチン「write_to_file」
–追記データ、追記対象ファイル、boolean(trueで追記)
on write_to_file(this_data, target_file, append_data)
  try
    set the target_file to the target_file as text
    
set the open_target_file to open for access file target_file with write permission
    
if append_data is false then set eof of the open_target_file to 0
    
write this_data to the open_target_file starting at eof
    
close access the open_target_file
    
return true
  on error error_message
    try
      close access file target_file
    end try
    
return error_message
  end try
end write_to_file

–ファイルの追記ルーチン「write_to_file」
–追記データ、追記対象ファイル、boolean(trueで追記)
on write_to_file_asRec(this_data, target_file, append_data)
  try
    set the target_file to the target_file as text
    
set the open_target_file to open for access file target_file with write permission
    
if append_data is false then set eof of the open_target_file to 0
    
write this_data to the open_target_file as record starting at eof
    
close access the open_target_file
    
return true
  on error error_message
    try
      close access file target_file
    end try
    
return error_message
  end try
end write_to_file_asRec

▼新規書類に ▼カーソル位置に ▼ドキュメント末尾に

2010/06/15 iChatの文字チャット経由で遠隔地のMacを操作

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

ic4.jpg

メッセージの先頭に「sh:」と書けば、その後の文字をシェルコマンドとして、「as:」と書けばその後の文字列をAppleScriptとして実行します。イタズラしようと思えば際限なくイタズラできてしまうので、たいへん危険なAppleScriptであり、取扱いに最大限の注意を必要とします。動作原理を理解できなかったり、シェルコマンドの実行に習熟していないユーザーには使用をすすめません。

Mac OS X 10.5以降、iChatごしに画面共有して遠隔地のMacをコントロールできるようになり、大変便利に活用しています。ただ、そうしたビデオチャットの環境がネットワーク的にできなかったりするケースもあり、それでもリモートコントロールしなければならない、といった事態も考えられます。

そこで、だいたいどこでもつながる文字チャットを使って、shellやAppleScriptのコマンドを送り、文字チャット経由で結果を確認することができるプログラムを(ちょろっと)書いてみました。とりあえず、2台のMacを並べてiChat経由でリモート操作できています。

まずは、動作原理の説明から。

ic1.jpg

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

ic0.jpg

それらの一環として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で実行するようにすれば、ワンショットの一発コマンドやり逃げではなく、もう少し実用性が出てくるのではないかと考えます。

ic3.jpg
▲shellコマンドでコントロール

ic2.jpg
▲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

▼新規書類に ▼カーソル位置に ▼ドキュメント末尾に