***添付ファイルの扱い -画像等の添付ファイルを指定することができます。 -添付ファイルは、PukiWikiに取り込む際にページの添付ファイルになります。 -画像が指定された場合に限り、本文の最後に &ref() で指定されます。 ***メールの取り込み +プラグインが記述された管理用のページを開きます。 +パスワードを入力し「メール取得」ボタンを押します。 +メールで送信された内容が編集ボックスに格納されます。~ ページ名は「引数に指定されたページ名/表題(Subject)」になります。 +ページ名が同じの場合、既存のページの後に追加されます。 +あとは通常の「編集」と同じです。 **管理用ページの設置方法 管理用のページにプラグインを指定します。 #contribute([ページ名]) -ページ名~ ページを追加するトップページ名を指定します。 省略した場合はルートに追加します。 **注意 -テキストファイルは全てメール本文とみなされます。 -メールに添付されたファイルは自動的にそのページの添付ファイルとなりますが、 ページを削除しても(登録しなくても)添付ファイルの削除は行いません。 -mailkeeperプラグインとは同じページに記述できません。 -最大受信サイズ(デフォルトでは100kbyte)を超えた場合、内容は保証されません ((それ未満でも保証しないわけですが・・・))。 -------------------------------*/ /* ja.lngに下記の定義を追加すること。 /////////////////////////////////////// // contribute.inc.php $contribute_msg = 'パスワードを入力してください。'; $contribute_invalid = 'パスワードが間違っています。'; $contribute_button = 'メール取得'; $contribute_pop_err = 'サーバーに接続できません。'; $contribute_none = '新しいメールはありません。'; */ ///////////////////////////////////////////////// // 下記の値を書き換えて使用すること! ///////////////////////////////////////////////// // メールサーバアドレス define('CONTRIBUTE_MAILSERVER','mail.server.address'); // User define('CONTRIBUTE_MAILUSER','username'); // Pass define('CONTRIBUTE_MAILPASS','password'); ///////////////////////////////////////////////// // POPメール受信クラスの定義値 // POP3ポート define('CONTRIBUTE_MAILPORT','110'); // タイムアウト define('CONTRIBUTE_MAILTMOUT','30'); // 受信最大サイズ(default=102400 100kbyte) define('CONTRIBUTE_MAXSIZE','102400'); // 受信最大サイズを超えたときの受信行数 define('CONTRIBUTE_RCVLINE','500'); ///////////////////////////////////////////////// // 受信したメールを消去する 1:消去 0:サーバに残す define('CONTRIBUTE_MAIL_DELETE','1'); // APOPによる認証 0:使用しない 1:使用する define('CONTRIBUTE_USE_APOP','0'); ///////////////////////////////////////////////// // last UID file define('CONTRIBUTE_FILE_UID',CACHE_DIR.'contribute_uid.dat'); ///////////////////////////////////////////////// // POPメール解析クラス class popmail_parse { var $plain, $header, $body; var $content_type, $content_subtype , $content_param , $content_encoding; var $content_disposition, $content_sub_disposition; var $to, $from, $msgid, $datetime, $subject; function popmail_parse($plain) { unset($this->plain); unset($this->header); unset($this->body); unset($this->content_type); unset($this->content_subtype); unset($this->content_param); unset($this->to); unset($this->from); unset($this->msgid); unset($this->datetime); unset($this->subject); $this->plain = $plain; } function analyze($plain) { // // Header 及び body の分離 // if($plain!='') { $this->plain = $plain; } $ex = explode( "\r\n\r\n" , $this->plain , 2 ); $header_temp = $ex[0]; $body_temp = $ex[1]; // // マルチラインヘッダーの正規化 // $header_array = explode( "\n" , $header_temp ); $this->header = ''; foreach( $header_array as $hl ) { $header_line = chop($hl); if( preg_match("/^\s+.*/",$header_line )==True ) { $this->header .= " " . ltrim($header_line); } else { $this->header .= "\n" . $header_line; } } $this->header .= "\n"; $this->body = $body_temp; // // Content-Type: のチェック // if( preg_match("/[\^\n]content-type: (\S+)\/(\S+)\s*;\s*(\S+)/i",$this->header,$match)==True ) { $this->content_type = $match[1]; $this->content_subtype = $match[2]; $this->content_param = $match[3]; } else if( preg_match("/[\^\n]content-type: (\S+)\/(\S+)/i",$this->header,$match)==True ) { $this->content_type = $match[1]; $this->content_subtype = $match[2]; $this->content_param = ""; } // // Content-Transfer-Encoding: のチェック // if( preg_match("/[\^\n]content-transfer-encoding: (\S+)/i",$this->header,$match)==True ) { $this->content_encoding = $match[1]; //echo $this->content_encoding."/ "; } // Content-Disposition: のチェック if( preg_match("/[\^\n]content-disposition: (\w+)\s*;\s*(\S+)/i",$this->header,$match)==True ) { $this->content_disposition = $match[1]; $this->content_sub_disposition = $match[2]; } // // To: のチェック // if( preg_match("/[\^\n]to:\s+<([\w\.\-]+@[\w\.\-]+)>/i",$this->header,$match)==True ) { $this->to = $match[1]; } else if( preg_match("/[\^\n]to:\s+([\w\.\-]+@[\w\.\-]+)/i",$this->header,$match)==True ) { $this->to = $match[1]; } // // From: のチェック // if( preg_match("/[\^\n]from:\s+.*<([\w\.\-]+@[\w\.\-]+)>/i",$this->header,$match)==True ) { $this->from = $match[1]; } else if( preg_match("/[\^\n]from:\s+([\w\.\-]+@[\w\.\-]+)/i",$this->header,$match)==True ) { $this->from = $match[1]; } // // Message-Id: のチェック // if( preg_match("/[\^\n]message-id:/i",$this->header,$match)==True ) { $this->msgid = $match[1]; } // 日付の抽出 $this->datetime = -1; if( preg_match("/[\^\n]date:[ \t]*([^\r\n]+)/i",$this->header,$match)==True ) { $this->datetime = strtotime($match[1]); } if ($this->datetime == -1) { $this->datetime = time(); } // サブジェクトの抽出 if (eregi("\nSubject:[ \t]*([^\r\n]+)", $this->header, $subreg)) { $this->subject = $subreg[1]; //MIME Bデコ−ド while (eregi("(.*)=\?iso-2022-jp\?B\?([^\?]+)\?=(.*)",$this->subject,$regs)) { $this->subject = $regs[1].base64_decode($regs[2]).$regs[3]; } //MIME Qデコ−ド while (eregi("(.*)=\?iso-2022-jp\?Q\?([^\?]+)\?=(.*)",$this->subject,$regs)) { $this->subject = $regs[1].quoted_printable_decode($regs[2]).$regs[3]; } if(function_exists('mb_convert_encoding')) { $this->subject = mb_convert_encoding($this->subject, "EUC-JP", "auto"); } $this->subject = htmlspecialchars($this->subject); } // // Multipartチェック(RFC2046) // (再帰呼び出し) // $content = strtolower($this->content_type) . "/" . strtolower($this->content_subtype); //echo $content . "/ \n"; if( $content=="multipart/mixed" || $content=="multipart/alternative" || $content=="multipart/parallel" || $content=="multipart/digest" ) { if( preg_match('/boundary="([^"]+)"/i' , $this->content_param , $match ) ) { $boundary = $match[1]; } else { return array(); } // echo "(!) Boundary => (" . $boundary . ")\n"; $bounding_array = explode( $boundary , $this->body ); $result = array(); foreach( $bounding_array as $id => $bounding_body ) { if( $id==0 ) continue; $bbody = new popmail_parse($bounding_body); $r = $bbody->analyze(); foreach( $r as $key => $data ) { $result[] = $data; } } return $result; } // // BASE64 / uuencode // if( $this->content_encoding=="base64" ) { $data = base64_decode($this->body); } else if( $this->content_encoding=="quoted-printable" ) { $data = quoted_printable_decode($this->body); } else { $data = $this->body; } if($content=="text/plain") { if(function_exists('mb_convert_encoding')) { // テキストをEUCへ変換する $data = mb_convert_encoding($data, "EUC-JP", "auto"); } } $filename = ''; if( preg_match("/name\=\"(\S+)\"/i",$this->content_param,$match)==True ) { // Content-Type: にname指定あり $filename = $match[1]; } if( preg_match("/filename\=\"(\S+)\"/i",$this->content_sub_disposition,$match)==True ) { // こちらがContent-Typeの指定より優先される // Content-Disposition: にfilename指定あり $filename = $match[1]; } $result[] = array("Content-Type" => $content , "Body" => $data , "Filename" => $filename); return $result; } function to() { return $this->to; } function from() { return $this->from; } function msgid() { return $this->msgid; } function datetime() { return strftime("%Y/%m/%d %H:%M:%S",$this->datetime); } function date() { return strftime("%Y-%m-%d",$this->datetime); } function body() { return $this->body; } function header() { return $this->header; } function subject() { return $this->subject; } function content_type() { return $this->content_type."/".$this->content_subtype; } } class pop3_protocol { var $sock; var $mailnum, $totalsize; var $uid, $break_flg; function pop3_protocol() { unset($this->sock); unset($this->mailnum); unset($this->totalsize); } ////////////////////////////////////////////////////////// // POP3接続を開始して受信メール件数とサイズを得る function connect($server,$pop_port,$timeout,$user,$pass,$apop) { // POP3接続開始 $this->sock = fsockopen($server, $pop_port, $err, $errno, $timeout); if($this->sock!=FALSE) { $buf = fgets($this->sock, 512); if(substr($buf, 0, 3) != '+OK') { die($buf); // サーバ接続エラー } if($apop==0) { // クリアテキスト認証 $buf = $this->sendcmd($this->sock,"USER $user"); $buf = $this->sendcmd($this->sock,"PASS $pass"); } else { // APOPを使用する if( preg_match("/^\+OK\s+.*(<+.*>)/",$buf,$match)==True ) { $apop = md5($match[1].$pass); $buf = $this->sendcmd($this->sock,"APOP $user $apop"); } } // 受信済みメールの件数とサイズを得る $buf = $this->sendcmd($this->sock,"STAT"); sscanf($buf, '+OK %d %d',$this->mailnum,$this->totalsize); } return $this->sock; } ////////////////////////////////////////////////////////// // POP3接続を終了する function disconnect() { $buf = $this->sendcmd($this->sock,"QUIT"); fclose($this->sock); } ////////////////////////////////////////////////////////// // 指定番号のメールを受信する function get_mail($num,$maxsize,$rcvline) { //UIDL n -n番目のUID取得 $buf = $this->sendcmd($this->sock,"UIDL $num"); sscanf($buf, '+OK %d %s',$dummy,$this->uid); //LIST n -n番目のサイズ取得(ヘッダ含) $buf = $this->sendcmd($this->sock,"LIST $num"); sscanf($buf, '+OK %d %ld',$dummy,$size); if($maxsize>0 && $size>$maxsize) { // 受信サイズ制限にかかった $buf = $this->sendcmd($this->sock,"TOP $num ".$rcvline); } else { //RETR n -n番目のメッセージ取得(ヘッダ含) $buf = $this->sendcmd($this->sock,"RETR $num"); } while (!ereg("^\.\r\n",$buf)) { //EOFの.まで読む $buf = fgets($this->sock,512); $data.= $buf; } // 取得したメールデータの検証 $mail_len = strlen($data) - 3; // LISTで取得したサイズと実際の受信データのサイズを比較 $this->break_flg = 0; if($mail_len != $size) { // TOPコマンド受信で全て受信できていない $this->break_flg = 1; } return $data; } ////////////////////////////////////////////////////////// // 指定番号のメールを消去する function delete_mail($num) { //DELE n n番目のメッセージ削除 $buf = $this->sendcmd($this->sock,"DELE $num"); } ////////////////////////////////////////////////////////// // 最後に取得したメールのUIDを得る function get_uid() { return $this->uid; } ////////////////////////////////////////////////////////// // 受信件数を返す function get_mailnum() { return $this->mailnum; } ////////////////////////////////////////////////////////// // 全受信メールのサイズを返す function get_totalsize() { return $this->totalsize; } ////////////////////////////////////////////////////////// // 新着メールの確認(0..新着メールなし) function check_newmail($last_uid) { $num = $this->mailnum; // 受信しているメール数 $newnum = 1; while($num>0) { //UIDL n -n番目のUID取得 $buf = $this->sendcmd($this->sock,"UIDL $num"); sscanf($buf, '+OK %d %s',$dummy,$check); if(strcmp($check,$last_uid)==0) { // 最後に受信したメールを見つけた if($num==$this->mailnum) { // 新着メールなし $newnum = 0; } else { $newnum = $num + 1; } break; } $num--; } // 一致しなければ、全てが新着メール return $newnum; } ////////////////////////////////////////////////////////// // 最後に受信したメールのUIDを得る function get_lastuid($file) { if(file_exists($file)) { $fp = fopen($file, 'r') or die('cannot open '.$file); $last_uid = rtrim(fgets($fp,256)); // ファイルを閉じる fclose($fp); } else { $last_uid = ''; } return $last_uid; } ////////////////////////////////////////////////////////// // 最後に受信したメールのUIDを保存する function set_lastuid($file) { $fp = fopen($file, 'w') or die('cannot write '.$file); set_file_buffer($fp, 0); flock($fp,LOCK_EX); rewind($fp); ftruncate($fp,0); fputs($fp,$this->uid); flock($fp,LOCK_UN); fclose($fp); } ////////////////////////////////////////////////////////// // 最後に受信したメールが破損しているかどうか function is_broken() { return $this->break_flg; } // POP3コマンド送信 function sendcmd($sock,$cmd) { fputs($sock, $cmd."\r\n"); $buf = fgets($sock, 512); if(substr($buf, 0, 3) == '+OK') { return $buf; } else { die($cmd." >> ".$buf); } } } // //------------------------------------------------------------------------ // プラグインの本体はここから //------------------------------------------------------------------------ // function plugin_contribute_action() { global $script,$vars,$post,$adminpass,$_title_edit; global $contribute_msg; global $contribute_invalid,$contribute_pop_err,$contribute_none; $pass = array_key_exists('pass' ,$post) ? $post['pass'] : NULL; $toppage = array_key_exists('toppage',$post) ? $post['toppage'] : NULL; $post['page'] = $vars['page'] = $vars['refer']; // パスワード確認 if(md5($pass) == $adminpass) { // パスワード一致 // POP接続開始 $pop = new pop3_protocol(); if($pop->connect(CONTRIBUTE_MAILSERVER, CONTRIBUTE_MAILPORT,CONTRIBUTE_MAILTMOUT, CONTRIBUTE_MAILUSER,CONTRIBUTE_MAILPASS,CONTRIBUTE_USE_APOP) == FALSE) { die($contribute_pop_err); } if(CONTRIBUTE_MAIL_DELETE!='1') { // メールを残す設定 $last_uid = $pop->get_lastuid(CONTRIBUTE_FILE_UID); // 新着メールの確認 $newnum = $pop->check_newmail($last_uid); } else { $newnum = 1; } if($newnum>0 && $pop->get_mailnum()>0) { // 1件のメッセージのみ取得する $maildata = $pop->get_mail($newnum,0,0); // メールの解析開始 $mail = new popmail_parse(); $result = $mail->analyze($maildata); //////////////////////////////////////////////// // 登録するページ名を決定する // メールページの登録フォーマット: // '[引数で指定されたページ名]/[Subject]' // $subject = $mail->subject(); if($toppage!='') { $toppage .= "/"; } $wpage = "$toppage$subject"; //////////////////////////////////////////////// // 本文取得 $postdata = get_source($wpage); if($postdata!='') { // 追記する $postdata .= "\n"; } // Content-Typeが"text/plain"のものを探す $str = ''; $img_attach = ''; $unknown_count = 0; foreach( $result as $key => $value ) { if( $value["Content-Type"]!="text/plain" ) { if($value["Body"]!='') { // ファイル名の取得 $filename = $value["Filename"]; if( $filename=='' ) { // ファイル名が不明な場合、適当なファイル名をつける $unknown_count++; $filename = "unknown$unknown_count.dat"; //echo $value["Content-Type"]; } if( preg_match("/^image\//i",$value["Content-Type"]) == True ) { // 画像リンク $img_attach .= "&ref($filename);\n"; } $basename = UPLOAD_DIR.encode($wpage).'_'.encode($filename); // 添付ファイルの保存 $fp = fopen($basename,'wb') or die_message('cannot write '.$basename); set_file_buffer($fp, 0); flock($fp,LOCK_EX); rewind($fp); fwrite($fp,$value["Body"]); flock($fp,LOCK_UN); fclose($fp); } } else { // テキスト $str .= $value["Body"]."\n"; } } $str = str_replace("\r","",$str); // 文末のドットを取る $str = str_replace("\n.\n","",$str); // 先頭ドットの回復を取る $str = str_replace("\n..","\n.",$str); // 文末の -- (バウンダリ)をとる(悪さしそう・・) $str = str_replace("\n--","",$str); // 本文を "auto"→"EUC-JP"へ変換する $str = mb_convert_encoding($str, "EUC-JP", "auto"); // 本文を確定する $postdata .= $str; if( $img_attach!='' ) { $postdata .= "\n$img_attach\n"; } if(CONTRIBUTE_MAIL_DELETE=='1') { // 全てが終了してからメールを消去する $pop->delete_mail($newnum); } else { // 最後に受信したメールのUIDを保存しておく $pop->set_lastuid(CONTRIBUTE_FILE_UID); } // 編集フォームにする $post['page'] = $vars['page'] = $wpage; // タイトルの"$1"を置換 $title = str_replace('$1',$wpage,$_title_edit); // 編集画面へ $body = edit_form($wpage,$postdata); } else { // メールがありませんでした $title = $contribute_none; $body = "

$title

"; } // POP接続の切断 $pop->disconnect(); } else { $title = ($pass === NULL) ? '' : "

$contribute_invalid

\n"; $body = "

$title

"; } $retvars['msg'] = $title; $retvars['body'] = $body; return $retvars; } function plugin_contribute_convert() { global $script,$vars; global $contribute_msg,$contribute_button; $toppage = ''; if(func_num_args()) { $args = func_get_args(); $toppage = array_shift($args); } $page = htmlspecialchars($vars['page']); $string = <<

$contribute_msg

EOD; return $string; } ?>