暗号化モジュール

 以前つくって,後になってバグがでてしまっていた暗号化モジュールなんですが,やっと作り直すことができました。ほとんどスクリプトを書き換えたのでかなり大変でしたが,うまく動作してくれているようです。

詳細

ライセンスご自由にお使いください。(NYSL
対応Hot Soup Processor ver.3.0 以上
種別HSPモジュール
/* Copyright (C) 2007-2009 By As(http://hp.vector.co.jp/authors/VA034028/) 文字処理機能付き暗号化モジュール ascrypt  //文字列の符号化を行う ascrypt_enc 暗号化を行う文字列の入った変数, キーの入った文字列型変数, 文字処理を行うアスキーコードが入った配列変数*1 //文字列の復号化を行う ascrypt_enc 暗号化を行う文字列の入った変数, キーの入った文字列型変数, 文字処理を行うアスキーコードが入った配列変数*1 *1 配列変数の0番目の配列は0x00で予約されているため,使用することは出来ません。1番目以降を使用してください また1番目以降においても,0x00~0x80までは使用できません //SAMPLE a = "test" key = "key" word = 0x00, 0x0a, 0x0d //改行させないようにする ascrypt_enc a, key, word */#define global ascrypt_enc(%1, %2, %3, %4=0xff) ascrypt 0, %1, %2, %3, %4#define global ascrypt_dec(%1, %2, %3) ascrypt 1, %1, %2, %3#module module_ascrypt//キー生成#deffunc ascrypt_keygen array _key, var _randomize, var _keystr, local s1, local s2, local s3, local s4, local s5
s1 = _keystr //キーの文字列が代入されるs2 = strlen(s1) //キーの文字数が代入される_randomize = 1randomize s2 //乱数の初期化repeatif rnd(2):s5=1:else:s5=-1 //ランダムに入れ替えるs3 = strf("%d", cnt)if instr(s3, 0, "3")!-1{//繰り返し回数に3が付く場合実行_key(cnt)=-rnd(33)*s5^rnd(s2)if _key(cnt) == 0 : _key(cnt) = 1continue}if cnt\5=0{//5の倍数の場合実行_key(cnt)=-rnd(55)*s5^rnd(s2)if _key(cnt) == 0 : _key(cnt) = 1continue}
_key(cnt)=peek(s1, s4)*s5^rnd(s2) //キー配列if _key(cnt) == 0 : _key(cnt) = 1_randomize+=rnd(_key(cnt)*_key(cnt))+1 //乱数初期化用数値s4++ //キーの位置のカウントif s4 = s2+1 : break //キーの最後まで行ったらループを抜けるloopreturn _randomize//単純な暗号化を行う(関数)#deffunc func_ascrypt_ecrypt int _type, var _var, int _randomize, int _rect, int _shift
randomize _randomize
repeat strlen(_var)switch _typecase 0poke _var, cnt, peek(_var, cnt) +rnd(_rect) + _shift
swbreakcase 1poke _var, cnt, peek(_var, cnt) -rnd(_rect) - _shift
swbreak
swend
loopreturn//単純な暗号化を行う(命令)#defcfunc ascrypt_ecrypt int _type, str _str, int _randomize, int _rect, int _shift, local s1
s1 = _str
randomize _randomize
repeat strlen(s1)switch _typecase 0poke s1, cnt, peek(s1, cnt) +rnd(_rect) + _shift
swbreakcase 1poke s1, cnt, peek(s1, cnt) -rnd(_rect) - _shift
swbreak
swend
loopreturn s1//処理文字の修正#deffunc ascrypt_worddisp var _var, array _word, int _wordlen, int _rect, int _shift, int _size_rect, int _size_shift, local s1, local s2, local s3, local s4, local s5, local s6, local s7, local s8, local s9, local s10
s1 = strlen(_var) //符号化されたデータの全体サイズs2 = int("$"+ascrypt_ecrypt(1, strmid(_var, s1-8, 8), s1, _size_rect, _size_shift)) //符号化する文字列のサイズif (s2 >=s1-_wordlen*8)|(s2 <=0) : return 0 //エラー回避s3 = strmid(_var, s2, s1-s2-8) //抽出した文字位置情報if s3 == "" : return 0 //エラー回避func_ascrypt_ecrypt 1, s3, s2, _rect, _shift //文字位置情報の復号s4 = strlen(s3) //抽出した文字位置情報のサイズrepeat _wordlen
s6 = cnt
s7 = int("$"+strmid(s3, s5,8))
repeat limit(s7, 0, s7)
s5 += 8poke _var, int("$"+strmid(s3, s5, 8)), _word(s6)
loop
s5 += 8loop
memset _var, 0x00, s1-s2, s2 //データ末端の位置情報を削除するreturn s2//符号化&暗号化を行う//ascrypt フラグ(0=符号化 | 1=復号化), 符号化もしくは復号化する文字列型変数, 鍵として使用する文字列, 文字処理を行うアスキーコードが入った配列変数#define size_cirect 26 //文字位置情報を符号化するための乱数範囲(size_cirect+size_shiftで26以上になるとエラーになります)#define size_shift 0 //文字位置情報を符号化するためのシフト範囲#define addcharinfo(%1, %2) s3+=%1 : s3+=strf("%08x", %2)#deffunc ascrypt int _type, var _var, var _key, array _word, int _afterword, local s1, local s2, local s3, local s4, local s5, local s6, local s7, local s8, local s9, local s10, local s11, local s12, local s13, local s14, local s15, local s16, local s17, local s18, local s19, local s20, local s21if (_var == "")|(_key == "") : _var = "" : return 0if _word(0) != 0x00 : dialog "処理する文字の配列変数の0番目に0x00以外の文字を指定することは出来ません",1,"ascryptエラー" : returns1 = length(_word)//文字位置情報で該当の文字にならないようにするs2 = 255repeat s1if _word(cnt) > s3 : s3 = _word(cnt)if _word(cnt) < s2 : s2 = _word(cnt)
loop
s4 = limit (s3-s2 + 1, 1, s3-s2 + 1)
s5 = limit (255 - s3 - s4, 1, 255 - s3 - s4)if _type == 0 {//置き換える文字列if (_afterword == 0x00)|(_afterword>255){
s6 = 0xff} else {
s6 = _afterword
}
}
sdim s7, 8 : sdim s8, 8 : sdim s9, 8 : sdim s10, 8, s1 : dim s11, s1
ascrypt_keygen s12, s13, _key //符号化に使われるキーを生成する//符号化データ 仕様//<符号化されたデータ><0x0D文字があった位置 int型ffffffff>...<0x0D文字の数 ffffffff><0x0D文字があった位置 int型ffffffff>...<NULL文字の数 ffffffff><int型の符号化されたデータのサイズ ffffffff><EOF>s14 = length(s12) //キー配列の数switch _typecase 0//符号化する場合s9 = strlen(_var) //符号化する文字列のサイズswbreakcase 1//復号化する場合ascrypt_worddisp _var, _word, s1, s5, s4, size_cirect, size_shiftif stat == 0 {//エラー処理_var = ""return 0}
s9 = stat //符号化する文字列のサイズswbreak
swend
randomize s13 //乱数の初期化repeat limit(s9, 0, s9) //符号化する文字列のサイズの分だけループif rnd(2) : s15 = 1 : else : s15 = -1 //ランダムに入れ替えるswitch _typecase 0//符号化poke s16, 0, peek(_var, cnt) + (rnd(s12(s17))+rnd(s13))*s15 //s16に一時的に符号化した文字を書き込みs18 = peek(s16, 0)//文字の処理を行うs19 = 0s20 = cnt
repeat s1if s18 == _word(cnt) {
poke _var, s20, s6 //書き換えるs10(cnt) += strf("%08x", s20)
s11(cnt)++
s21 += 8s19 = 1break}
loopif s19 == 0 : poke _var, cnt, s16 //符号化データの書き込みswbreakcase 1//復号化poke _var, cnt, peek(_var, cnt) - (rnd(s12(s17))+rnd(s13))*s15 //直接符号化データを復号化swbreak
swend
s17++ //キーコードのカウントif s17>=s14 : s17 = 0 //キーコードのループloopif _type == 0{//符号化する場合sdim s14//ascrypt_worddisp_addinfo s14, s1 //位置情報の追加repeat s1
s14 += strf("%08x", s11(cnt))
s14 += s10(cnt)
s21 += 8loop
s12=s9 + 8 + s21 //文字情報も含む符号化データ全体のサイズmemexpand _var, s12 //メモリの再確保//符号化データの代入_var+=ascrypt_ecrypt(0, s14, s9, s5, s4) + ascrypt_ecrypt(0, strf("%08x", s9), s12, size_cirect, size_shift)
}return s12
#global#define SAMPLE 0/////サンプル1///////////////////////////////////////////////////////////#if SAMPLE == 1sdim a,4080sdim key,1024sdim b,4080key="test"a="test"word=0x00, 0x0A, 0x0Dinput key,ginfo_winx,21mesbox a, ginfo_winx, 200, 3button gosub "暗号化",*go
button gosub "復号化",*go2
mesbox b, ginfo_winx, 200, 3stop
*go
b=a
ascrypt_enc b, key, word
objprm 4,breturn*go2
a=b
ascrypt_dec a, key, word
objprm 1,areturn#endif/////サンプル2///////////////////////////////////////////////////////////#if SAMPLE == 2sdim a
sdim key
sdim b
a="test"key="test"word = 0x00, 0x0a, 0x0dascrypt_enc a, key, word
sdim key2, 256sdim key, 256b=a
input key2,ginfo_winx,21mesbox a, ginfo_winx, 200, 4//button gosub "暗号化",*gobutton gosub "復号化",*go2
mesbox b, ginfo_winx, 200, 4gsel 0,1stop
*go
b=a
ascrypt_enc b, key2, word
objprm 3,breturn*go2
b=a
ascrypt_dec b, key2, word
objprm 3,breturn#endif///////サンプル3//////////////////////////////////////////////////////////////#if SAMPLE == 3font msgothic,14,16 : pos 5,5objmode 2 : objsize ginfo_winx-10,200a={" ascryptをお試しいただき有難う御座います。この暗号化モジュールには文字処理機能が付いており,ヌル文字(0x00)や改行コード(0x0a,0x0d)などの文字列操作でなにかとバグの原因となってしまう文字をバグが発生しないほかの文字と置き換えることが出来るようになっています。
 例えば,ヌル文字と改行文字を暗号化されたデータに入れたくない場合は下のようにします。
\ta = "test"\tkey = "我輩は猫である。"\tword = 0x00, 0x0a, 0x0d\tascrypt_enc a, key, word
 aが暗号化される元のデータが入った文字列型変数,keyは復号化で必要になる鍵が入った文字列方変数,wordが文字処理を行う文字が入った配列変数です。この文字処理配列変数に含まれている文字コードは暗号化データには含まれることがありません。また,配列変数の0番目の配列は0x00で予約されているため,使用することは出来ません。ユーザーは,1番目から文字コードを指定する必要があります。
 また,同スクリプトには3つのサンプルが含まれています。「#define SAMPLE *」にてサンプルを切り替えることができます。"}key = "我輩は猫である。"#if 1//全ての文字を処理するrepeat 256word(cnt) = cnt
loop#else//ヌル文字と改行文字とタブ文字を処理word = 0x00, 0x0d, 0x0a, '\n'#endifascrypt_enc a, key, word, '0xff'
mes "符号化:"mesbox a,,,3b=a
ascrypt_dec b, key, word
mes "復号化:"mesbox b,,,3#endif#undef SAMPLE

UNIX時間 1234567890

f:id:As_hsp:20090206231716j:image

#uselib "crtdll.dll"#func time "time" sptr
repeat
redraw 0color : boxf : color 255,255,255 : pos 0,0time(varptr(a))
mes a
mes "1234567890まであと残り "+(1234567890-a)+" 秒\n\n"mes {"#uselib "crtdll.dll"#func time "time" sptr
repeat
redraw 0color : boxf : color 255,255,255 : pos 0,0time(varptr(a))
mes a
mes "1234567890まであと残り "+(1234567890-a)+" 秒\n\n"mes {\"\"}redraw 1wait 1loop"}redraw 1wait 1loop

HSPでIRCクライアントを作成してみた

 IRCサーバーをWindowsでリンクさせようと足掻いては見たものの、全く出来ずただ時間を無駄にしてしまった。
そんなわけで、やけになってHSPでモジュール変数を利用したIRCクライアントを作ってみた。

 C++でいうオブジェクト指向のような形でプログラムが書けるので、サーバー単位でオブジェクトを生成。

newmod irc,ircc, 0, "127.0.0.1", 6667, "", "NICKNAME", "USERNAME", "HOST NAME", "SERVER NAME", "REAL NAME", 63, 1

 この場合、127.0.0.1 が、接続先のIRCサーバーになり、6667はポートになります。
  newmodでオブジェクトを生成したら、その下にmod_ircc_connectを定義します。ircというのはモジュール変数です。C++でいえば、クラスのようなもの。

mod_ircc_connect ircif stat==1{
title "connected"oncmd gosub *IRCC_TIMER, WM_TIMER
}

 接続に成功すると、*IRCC_TIMERラベルにWM_TIMERメッセージが受け取られるたびにジャンプするようになります。

&#42;IRCC_TIMER
mod_ircc_timer ircif stat==1{
mod_ircc_join irc, "#test,#test2,#test3"}

 IRCC_TIMERラベルには、mod_ircc_timer命令を定義し
戻り値(stat)には、正常終了なら0、最初に接続が成功したときだけ1が返ります。
 この場合、statの値が1になった場合に、mod_ircc_joinが呼び出されます。
 mod_ircc_joinは、チャンネルの入室を行う命令で、指定されたモジュール変数(サーバー)に対して、#test, #test2, #test3 の部屋へ入室するようになります。

 IRC制御のほとんどの作業は、このラベルの中で行うようになります。

 マクロ機能もあり、mod_ircc_instr_privmsgやmod_ircc_instr_noticeなどの命令を追加することで、ユーザーは、チャンネル参加者の発言に含まれている言葉に反応して、処理を返すことが出来ます。

mod_ircc_instr_privmsg irc, "#test", "時報"if stat==1{
mod_ircc_notice irc, "#test", "今"+gettime(4)+"時です"}

 いまのところ入室、退室、PRIVMSG、NOTICE、マクロ、オペレータ権限の配布、PONGの返答などの機能が使えますが、BOTとしては使えてもまだまだクライアントとしてはもうすこし機能がほしいところ。

更新履歴

0.001
  • サーバーとの接続とデータの受信用タイマーループを一緒にした
0.002
  • mod_ircc_instr系命令のモジュール変数を統一
0.003
  • AAなど一括してデータが転送されたときに、mod_ircc_instr系命令で処理が抜けるバグを修正
0.004
  • オペレーターの変更を可能に
0.005
  • 発言にスペースが含まれていた場合に、正常に取得できていなかった問題を修正
  • 文字コード変換が正常に行われていなかったのを修正
  • データが送られてきた場合と、延期された作業がある場合のみデータの処理を行うように修正
  • mod_ircc_deconnect命令の追加
  • デバッグウィンドウの画面表示を変更
  • mod_ircc_timer命令の戻り値を変更
  • コマンドの条件分岐方法をelseifからswitchに変更
  • 文字列を分割する関数を二重に使うことで、文字列解析を行うようにした
  • 使用されていなかったモジュール変数の削除
0.006
  • ログをモジュール外に出力する命令を実装
  • ログを整形し表示させる命令を実装

mod_ircc.hsp

 ご自由にお使いください。また,このモジュールを実行するためには、 pcbnet2プラグインとHSP開発Wiki/文字コード変換モジュール が必要になります。 pcbnet2は、開発元がサイトを閉鎖したために、Shark++氏が再頒布しています。また、文字コード変換モジュールはShark++氏のソースコードです。

ダウンロード:mod_ircc.zip

#include "mod_encode.hsp" //http://hspdev-wiki.net/?Module%2F%CA%B8%BB%FA%A5%B3%A1%BC%A5%C9%CA%D1%B4%B9%A5%E2%A5%B8%A5%E5%A1%BC%A5%EB/////////////////////////////////// Created By As 0.006 //// IRCクライアントモジュール ///////////////////////////////////#define _irc_debug_ 0#ifndef WM_TIMER#define global WM_TIMER $00000113#endif#module//文字列分割 ircc_strcut 配列変数, 読み出す文字列, 区切る文字#deffunc ircc_strcut array p1, str p2, str p3, int _limit, local s1, local s2, local s3, local s4, local s5, local s6
s1=p2 //読み出す文字列を他のローカル変数に代入s4=p3 //区切る文字s5=strlen(s4)
sdim p1
repeat
s2=instr(s1,s3,p3)if s2=-1{//見つからない場合getstr p1(cnt), s1, s6break}else{if cnt>0:if _limit=cnt{
getstr p1(cnt), s1, s6break}
s3+=s2 //見つかった場合s2を加算if s3-s6>0{
p1(cnt)=strmid(s1,s6,s3-s6)
}else{
p1(cnt)=""}
s3+=s5 //区切る文字数分増やすs6=s3 //コピー開始位置の保持}
loopreturn//配列変数を指定した文字列で結合する//ircc_strcat 出力する変数, 配列変数, 区切る文字#deffunc ircc_strcat var _var, array _array, str _str, local s1
sdim s1,64repeat length(_array)-1s1+=_array(cnt)+_str
loop
s1+=_array(length(_array)-1)
_var=s1return#global//ircクライアントモジュール#module ircc m_sockid, m_server, m_port, m_pass, m_nickname, m_username, m_hostname, m_realname, m_servername, m_log, m_logsellen, m_timerid, m_debugscreenid, m_new_channel, m_new_command, m_new_p1, m_new_p2, m_new_p3, m_new_p4, m_new_p5, m_connect, m_connected, m_hit, m_channellog, m_channellogname, m_nickname_s, m_nickname_e, m_nickname_accs, m_command_s, m_command_e#include "pcbnet.as"#uselib "user32.dll"#func SetTimer "SetTimer" sptr,sptr,sptr,sptr
#func KillTimer "KillTimer" sptr,sptr
#func PostMessage "PostMessageA" int,int,int,int#define sjis2jis(%1, %2) _FromSJIS@mod_encode %2, CODEPAGE_S_JIS, %1, CODEPAGE_JIS#define ctype jis2sjis(%1) _ToSJIS@mod_encode(%1, CODEPAGE_JIS, CODEPAGE_S_JIS)//コンストラクタ//_log ログが保持される変数//_sockid ソケットID//_server 接続するホスト先//_port ポート//_pass 接続に必要案パスワード//_nickname ニックネーム//_username ユーザーネーム//_hostname ホストネーム//_servername サーバーネーム//_realname リアルネーム//_debugscreenid デバッグ用ウィンドウ(初期値:63)//_timerid タイマーID(初期値:1) ※この値は必要ない限り変えないで下さい#modinit int _sockid, str _server, int _port, str _pass, str _nickname, str _username , str _hostname, str _servername, str _realname,int _debugscreenid, int _timerid, local s1
m_sockid = _sockid
m_server = _server
m_port = _port
m_pass = _pass
m_nickname = _nickname
m_username = _username
m_hostname = _hostname
m_servername = _servername
m_realname = _realname
sdim m_channellog
sdim m_channellogname
sdim m_log,64m_logsellen = 30 //ログの最大行数if _timerid=0{
m_timerid=1}else{
m_timerid=_timerid
}
sdim m_new_channel
sdim m_new_command
sdim m_new_p1
sdim m_new_p2
sdim m_new_p3
sdim m_new_p4
sdim m_new_p5
m_nickname_s="("m_nickname_e=")"m_nickname_accs="*"m_command_s="("m_command_e=")"#ifdef _debugs1=ginfo_selif _debugscreenid=0{
m_debugscreenid=63}else{
m_debugscreenid = _debugscreenid //デバッグ用ウィンドウのスクリーンIDを指定します}
dcount++
screen m_debugscreenid, 640,480mesbox m_log,ginfo_winx,ginfo_winy
gsel s1#endifreturn#ifdef _debug#modfunc mod_ircc_logreflesh local _ginfo_sel, local _m_logsize
_ginfo_sel=ginfo_sel
gsel m_debugscreenid
objprm 0,m_log
gsel _ginfo_selreturn#modfunc mod_ircc_debug_title str _title, local _ginfo_sel
_ginfo_sel=ginfo_sel
gsel m_debugscreenid
title _title
gsel _ginfo_selreturn#endif#modfunc mod_ircc_addlog str _str
m_log+=_str//ログが増えた場合削除notesel m_log
repeat notemaxif notemax>m_logsellen{
notedel 0continue}
loop
noteunsel#ifdef _debugmod_ircc_logreflesh thismod#endifreturn//ログ用変数のクローン変数化#modfunc mod_ircc_duplog var _var
dup _var, m_logreturn//IRCサーバーに接続//戻り値//1 = 接続完了//0 = 接続エラー#modfunc mod_ircc_connect local s1, local s2, local s3, local x1, local x2, local size, local connected
tcpopen m_sockid, m_server, m_port //IRCサーバーの接続を開始repeat 6000tcpiscon m_sockidif stat==1{
connected=1break}else:if stat==2{ #ifdef _debugmod_ircc_addlog thismod, "IRCC: tcpopen error.\n" #endifbreak}
wait 1loopif connected=1{
SetTimer hwnd, m_timerid, 500, 0}return connected//IRCサーバーから切断#modfunc mod_ircc_deconnectif varuse(thismod)==0:returnm_connect=0m_connected=0sdim m_new_channel
sdim m_new_command
sdim m_new_p1
sdim m_new_p2
sdim m_new_p3
sdim m_new_p4
sdim m_new_p5
KillTimer hwnd, m_timerid
tcpshut m_sockid
tcpclose m_sockid #ifdef _debugmod_ircc_addlog thismod, "IRCC: サーバーから切断しました" #endifreturn//ex.mod_ircc_channellogstyle irc, "(", ")", "*", "(", ")"#modfunc mod_ircc_channellogstyle str _nickname_s, str _nickname_e, str _nickname_accs, str _command_s, str _command_e
m_nickname_s=_nickname_s
m_nickname_e=_nickname_e
m_nickname_accs=_nickname_accs
m_command_s=_command_s
m_command_e=_command_ereturn//チャンネルログに追加#modfunc mod_ircc_addchannellog str _channelname, str _command, str _p1, str _p2, str _p3, str _p4, str _p5, local fclog, local fccnt, local timelog, local fcnameif _channelname!""{
foreach m_channellognameif m_channellogname(cnt) == _channelname{
fclog=1fccnt=cntbreak}
loop
}else{
fclog=2 //全てのチャンネルが対象}if fclog == 0{if m_channellogname(0)==""{
fccnt=0}else{
fccnt=length(m_channellogname)
}
m_channellogname(fccnt)=_channelname
}
timelog=strf("%02d", gettime(4))+":"+strf("%02d", gettime(5))
foreach m_channellogname
notesel m_channellog(fccnt)switch _commandcase "PRIVMSG"ircc_strcut fcname, _p1, "!"noteadd timelog+" "+m_nickname_s+fcname+m_nickname_e+" "+_p2, -1swbreakcase "NOTICE"ircc_strcut fcname, _p1, "!"noteadd timelog+" "+m_nickname_s+fcname+m_nickname_e+" "+_p2, -1swbreakcase "JOIN"ircc_strcut fcname, _p1, "!"noteadd timelog+" "+m_nickname_accs+fcname+" join "+_channelname+" "+m_command_s+fcname(1)+m_command_e, -1swbreakcase "QUIT"ircc_strcut fcname, _p1, "!"noteadd timelog+" "+m_nickname_accs+fcname+" quit "+m_command_s+_p1+m_command_e, -1swbreakcase "PART"ircc_strcut fcname, _p1, "!"noteadd timelog+" "+m_nickname_accs+fcname+" part "+m_command_s+_p2+m_command_e, -1swbreakcase "TOPIC"ircc_strcut fcname, _p1, "!"noteadd timelog+" "+m_nickname_accs+fcname+" topic : "+_p2, -1swbreak
swend
fccnt++
noteunselif fclog!2:breakloopreturn//入室#modfunc mod_ircc_join str _channelname, local s1if _channelname="":returnmod_ircc_addlog thismod, "JOIN "+_channelname+"\n"ircc_strcut s1,_channelname,","foreach s1
tcpput "JOIN "+s1(cnt)+"\n", m_sockid
loopreturn//退室#modfunc mod_ircc_part str _channelname, str _partmessage, local s1, local s2if _channelname="":returnif _partmessage!""{
s1=" :"+_partmessage
}
mod_ircc_addlog thismod, "PART "+_channelname+s1+"\n"mod_ircc_addchannellog thismod, _channelname, "PART", m_nickname, _partmessage, "", "", ""ircc_strcut s2,_channelname,","foreach s2
tcpput "PART "+s2(cnt)+s1+"\n", m_sockid
loopreturn//notice発言#modfunc mod_ircc_notice str _channelname, str _message, local s1if _message="":returnif _channelname="":returnmod_ircc_addlog thismod, "NOTICE "+_channelname+" :"+_message+"\n"ircc_strcut s1,_channelname,","foreach s1
mod_ircc_addchannellog thismod, s1(cnt), "NOTICE", m_nickname, _message, "", "", ""tcpput "NOTICE "+s1(cnt)+" :"+_message+"\n", m_sockid
loopreturn//PRIVMSG発言#modfunc mod_ircc_privmsg str _channelname, str _message, local s1if _message="":returnif _channelname="":returnmod_ircc_addlog thismod, "privmsg "+_channelname+" :"+_message+"\n"ircc_strcut s1,_channelname,","foreach s1
mod_ircc_addchannellog thismod, s1(cnt), "PRIVMSG", m_nickname, _message, "", "", ""tcpput "privmsg "+s1(cnt)+" :"+_message+"\n", m_sockid
loopreturn//オペレータ権限の操作//_flagが0以上でオペレータ権限を与えます#modfunc mod_ircc_vestoper str _channelname, str _nickname, int _flag, local s1if _flag<0:s1="-o":else:s1="+o"mod_ircc_addlog thismod, "MODE "+_channelname+" "+s1+" "+_nickname+"\n"tcpput "MODE "+_channelname+" "+s1+" "+_nickname+"\n", m_sockidreturn//延期作業リストに追加#modfunc mod_new_add str _channelname, str _command, str _p1, str _p2, str _p3, str _p4, str _p5
repeatif length(m_new_channel)<=cnt{
m_new_channel(cnt)=_channelname
m_new_command(cnt)=_command
m_new_p1(cnt)=_p1
m_new_p2(cnt)=_p2
m_new_p3(cnt)=_p3
m_new_p4(cnt)=_p4
m_new_p5(cnt)=_p5break}else:if m_new_channel(cnt)=""{
m_new_channel(cnt)=_channelname
m_new_command(cnt)=_command
m_new_p1(cnt)=_p1
m_new_p2(cnt)=_p2
m_new_p3(cnt)=_p3
m_new_p4(cnt)=_p4
m_new_p5(cnt)=_p5break}
loopreturn//接続のための情報を送信#modfunc mod_ircc_connect_infosendif m_pass!""{
tcpput "PASS "+m_pass+"\n", m_sockid
mod_ircc_addlog thismod, "PASS "+m_pass+"\n"if stat!0:mod_ircc_addlog thismod, "IRCC: PASSを送れませんでした\n"}
tcpput "NICK "+m_nickname+"\n", m_sockidif stat!0:mod_ircc_addlog thismod, "IRCC: NICKを送れませんでした\n"mod_ircc_addlog thismod, "NICK "+m_nickname+"\n"tcpput "USER "+m_username+" "+m_hostname+" "+m_servername+" :"+m_realname+"\n", m_sockidif stat!0:mod_ircc_addlog thismod, "IRCC: USERを送れませんでした\n"mod_ircc_addlog thismod, "USER "+m_username+" "+m_hostname+" "+m_servername+" :"+m_realname+"\n"return//指定されたチャンネルの整形されたチャンネルログを取得//この命令を実行すると、モジュール変数に保持してあるチャンネルログが初期化されます//ログを蓄積させる場合は、別途に変数を容易させる必要があります//戻り値 取得された場合1が返ります#modfunc mod_ircc_getchannellog var _var, str _channelname, local gcflag
foreach m_channellognameif m_channellogname(cnt) == _channelname{if m_channellog(cnt)!""{
_var = m_channellog(cnt)
m_channellog(cnt)=""gcflag=1}break}
loopif gcflag==0{
_var=""}return gcflag//タイマー管理//戻り値// 0 = 正常終了// 1 = ユーザー情報が登録された// 2 = サーバーからデータを受信した// -1 = 接続エラー#modfunc mod_ircc_timer local get, local s1, local s2, local s3, local s4, local s5, local s6, local x1, local x2, local x3, local size, local flagif m_connect=0{
mod_ircc_connect_infosend thismod
m_connect=1}
tcpfail m_sockidif stat==2{ #ifdef _debugmod_ircc_addlog thismod, "IRCC :通信が切断されました\nIRCC: このモジュール変数はdelmodによって削除されます\nIRCC :mod_ircc_timerの戻り値に-1が返されました\n開発者はこの戻り値で再接続をするプログラムを書くことが出来ます\n" #endifdelmod thismodreturn -1}
sdim s3,64repeat 120tcpcount s1, m_sockidif s1>0 {
sdim s2, s1+1tcpget s2, s1, m_sockid
s3+=s2
wait 0}else:breakloop#ifdef _debugmod_ircc_debug_title thismod, "【IRCデバッグ】処理スルー回数:"+cc+" 処理回数:"+cc2+" 合計:"+(cc+cc2)#endifif s3==""{//各mod_ircc_instr_系命令でひとつも該当するものがなかった場合(m_hit=0)初期化するif m_hit=0{//初期化sdim m_new_channel
sdim m_new_command
sdim m_new_p1
sdim m_new_p2
sdim m_new_p3
sdim m_new_p4
sdim m_new_p5
}else{
m_hit=0flag=2} #ifdef _debugcc++ #endifreturn flag
}else{
s3 = jis2sjis(s3)if m_connected==1 : flag = 2}
notesel s3
repeat notemax
noteget s4,cnt//改行コードが含まれているバグのfixif peek(s4)=10: getstr s4 ,s4, 1mod_ircc_addlog thismod, s4+"\n"ircc_strcut s5, s4, ":", 2//文字列解析s6 = length(s5)if s6>=1{
ircc_strcut x1, s5(0), " "if s6>=2{
ircc_strcut x2, s5(1), " "if s6>=3{
x3=s5(2)
}
}
} #if 0 #ifdef _debug mod_ircc_addlog thismod, "IRCC: s5(0): "+s5(0)+"\n" if x1!0 : mod_ircc_addlog thismod, "IRCC: x1(0): "+x1(0)+"\n" if x2!0 : mod_ircc_addlog thismod, "IRCC: x2(0): "+x2(0)+"\n" if x3!0 : mod_ircc_addlog thismod, "IRCC: x3(0): "+x3(0)+"\n" if x4!0 : mod_ircc_addlog thismod, "IRCC: x4(0): "+x4(0)+"\n" if x5!0 : mod_ircc_addlog thismod, "IRCC: x5(0): "+x5(0)+"\n" mod_ircc_addlog thismod, "\n" #endif #endif//PONGif x1(0)="PING"{
tcpput "PONG :"+m_nickname+"\n", m_sockid
mod_ircc_addlog thismod, "PONG :"+m_nickname+"\n"flag=0}if length(x2)>=2{switch x2(1)case "JOIN"mod_ircc_addchannellog thismod, x3, x2(1), x2(0), "", "", "", ""mod_new_add thismod, x3, x2(1), x2(0), "", "", "", ""swbreakcase "PRIVMSG"mod_new_add thismod, x2(2), x2(1), x3, "", "", "", ""mod_ircc_addchannellog thismod, x2(2), x2(1), x2(0), x3, "", "", ""swbreakcase "NOTICE"mod_new_add thismod, x2(2), x2(1), x3, "", "", "", ""mod_ircc_addchannellog thismod, x2(2), x2(1), x2(0), x3, "", "", ""swbreakcase "001"mod_ircc_addchannellog thismod, x2(2), x2(1), x3, "", "", "", ""flag=1m_connected=1swbreakcase "433"mod_ircc_addchannellog thismod, x2(2), x2(1), x3, "", "", "", ""//ニックネームがすでに使われている場合m_nickname+="_" //アンダーバー(_)を追加mod_ircc_connect_infosend thismod
swbreakcase "QUIT"mod_ircc_addchannellog thismod, "", x2(1), x2(0), x3, "", "", ""mod_new_add thismod, x2(2), x2(1), x3, "", "", "", ""swbreakcase "PART"mod_ircc_addchannellog thismod, x2(2), x2(1), x2(0), x3, "", "", ""mod_new_add thismod, x2(2), x2(1), x3, "", "", "", ""swbreakcase "TOPIC"mod_ircc_addchannellog thismod, x2(2), x2(1), x2(0), x3, "", "", ""mod_new_add thismod, x2(2), x2(1), x3, "", "", "", ""swbreakcase "MODE"mod_ircc_addchannellog thismod, x2(2), x2(1), x2(3), "x2(4)", "", "", ""//p1 モードの種類 p2 ターゲットmod_new_add thismod, x2(2), x2(1), x2(3), "x2(4)", "", "", ""swbreak
swend
}
loop#ifdef _debugcc2++#endifreturn flag
#modfunc mod_new_clear int _cnt
m_new_channel(_cnt)=""m_new_command(_cnt)=""m_new_p1(_cnt)=""m_new_p2(_cnt)=""m_new_p3(_cnt)=""m_new_p4(_cnt)=""m_new_p5(_cnt)=""return//TODO: ニックネームとサーバーとチャンネルの判定を分ける//TODO: ニックネームも判定のひとつに//TODO: オリジナルの名前とメッセージを取得できるように//指定されたチャンネルまたはサーバーまたはニックネームの最新のPRIVMSGに指定された文字列が含まれていた場合、1を返す//この命令は、WM_TIMER内mod_ircc_timer以降に入れて使用します//_flag: 1を指定すると、同じ発言に対して他の命令の判定も続けることができます#modfunc mod_ircc_instr_privmsg str _channelname, str _inmessage, int _flag, local _stat
foreach m_new_channelif m_new_channel(cnt)=_channelname{if m_new_command(cnt)="PRIVMSG"{if instr(m_new_p1(cnt), 0, _inmessage)!-1{if _flag=0 : mod_new_clear thismod, cnt
_stat=1m_hit=1break}
}
}
loopreturn _stat//指定されたチャンネルまたはサーバーまたはニックネームの最新のNOTICEに指定された文字列が含まれていた場合、1を返す ※非推奨//この命令は、WM_TIMER内mod_ircc_timer以降に入れて使用します#modfunc mod_ircc_instr_notice str _channelname, str _inmessage, int _flag, local _stat
foreach m_new_channelif m_new_channel(cnt)=_channelname{if m_new_command(cnt)="NOTICE"{if instr(m_new_p1(cnt), 0, _inmessage)!-1{if _flag=0 : mod_new_clear thismod, cnt
_stat=1m_hit=1break}
}
}
loopreturn _stat//入室を知らせる#modfunc mod_ircc_instr_join str _channelname, str _nickname, local _stat, local s1, local s2
ircc_strcut s1, _channelname, ","foreach s1
foreach m_new_channelif m_new_channel(cnt)=s1(s2){if m_new_command(cnt)="JOIN"{if (_nickname=="")|(instr(m_new_p1(cnt), 0, _nickname)!-1){
_stat = 1}
}
}
loop
s2++
loopreturn _stat
#modterm
KillTimer hwnd, m_timerid
tcpshut m_sockid
tcpclose m_sockid
netclearreturn#global//////// サンプルスクリプト ///////////////////////////////////////////////////////////////////////#if _irc_debug_gsel 0//左から、 モジュール変数,モジュール名, 接続するホスト, ポート, パスワード, ニックネーム...newmod irc,ircc, 0, "127.0.0.1", 6667, "", "TEST", "TEST", "TEST", "TEST", "TEST", 0, 1mes "接続を開始しています"//サーバーに接続します。この時点ではまだ、ユーザー情報をサーバーに登録していません。mod_ircc_connect ircif stat==1{//接続に成功したmes "接続が完了しました"title "connected"oncmd gosub *IRCC_TIMER, WM_TIMER
sdim clog,64mesbox clog, ginfo_winx,200}else{//接続に失敗mes "接続に失敗しました"}
stop//複数のサーバーに同時に接続する場合は、同じWM_TIMERのラベルに定義してください*IRCC_TIMER
mod_ircc_timer irc //ユーザー登録と定期的な受信(50ミリ秒)switch stat//サーバーにユーザー情報が登録されたcase 1mes "サーバーに登録が完了しました"mod_ircc_join irc, "#test,#test2,#test3,#test4,#test5" //部屋の入室mod_ircc_part irc, "#test3,#test4,#test5", "Bye" //#test3,#test4,#test5の部屋からメッセージを付けて退室swbreak//データが受信されたcase 2mes "データ受信"mod_ircc_instr_join irc, "#test,#test2", "TEST"if stat{
mod_ircc_privmsg irc, "#test,#test2", "やあこんばんは" //#test,#test2の部屋に発言 }
mod_ircc_instr_privmsg irc, "#test", "時報" //最新のPRIVMSGの中に“時報”が含まれていた場合1を返すif stat{
mod_ircc_notice irc,"#test","今"+gettime(4)+"時"+gettime(5)+"分です" //NOTICE発言を行う}
mod_ircc_instr_privmsg irc, "#test", "再起動" //最新のNOTICEの中に“時報”が含まれていた場合1を返すif stat{
mod_ircc_addlog irc, "再起動開始\n" //ログに文字列を追加する*@
mod_ircc_deconnect irc
mod_ircc_connect irc //サーバーへ接続if stat==1{//接続成功title "connected"oncmd gosub *IRCC_TIMER, WM_TIMER
}else{//接続失敗mes "接続できませんでした1分後に再接続します"wait 6000goto *@b
}
}
swbreak//サーバーから切断されたcase -1*@
mes "サーバーから切断されました1分後に再接続します"//サーバーから切断されたら1分後に再接続wait 6000//新しくオブジェクトを作成mod_ircc_deconnect irc
mod_ircc_connect irc //サーバーへ接続if stat==1{//接続成功title "connected"oncmd gosub *IRCC_TIMER, WM_TIMER
}else{//接続失敗mes "接続できませんでした"goto *@b
}
wait 0swbreak
swend//"#test"チャンネルのログを取得するmod_ircc_getchannellog irc, log, "#test"if stat{
clog+=log
objprm 0,clog
}return#endif