| 1 | #!/usr/bin/php |
|---|
| 2 | <? |
|---|
| 3 | |
|---|
| 4 | # ml.py -- simple mailing list to just distribute messages in a group. |
|---|
| 5 | # Copyright (c) 2007 Shigeru KANEMOTO |
|---|
| 6 | # All rights reserved. |
|---|
| 7 | |
|---|
| 8 | define('ML_LIST_ADDRESS', 'list@example.com'); |
|---|
| 9 | $ML_LIST_SUBSCRIBERS = array( |
|---|
| 10 | # 'email address (lower case)' => 'real name' |
|---|
| 11 | "somebody@example.com" => "�ʤޤ�" |
|---|
| 12 | ); |
|---|
| 13 | |
|---|
| 14 | define('ML_EMAIL_MAX_SIZE', 100000); |
|---|
| 15 | define('ML_CHARSET', 'iso-2022-jp'); |
|---|
| 16 | define('ML_CODE_CHARSET', 'euc-jp'); // encoding of this source code. |
|---|
| 17 | |
|---|
| 18 | //////////////////////////////////////////////////////////////////////////////// |
|---|
| 19 | |
|---|
| 20 | // �饤�֥� |
|---|
| 21 | require_once('PEAR.php'); |
|---|
| 22 | require_once('Mail.php'); |
|---|
| 23 | require_once('Mail/mime.php'); |
|---|
| 24 | require_once('Mail/mimeDecode.php'); |
|---|
| 25 | require_once('Mail/RFC822.php'); |
|---|
| 26 | |
|---|
| 27 | function decodeSingleAddress($s) { |
|---|
| 28 | $a = Mail_RFC822::parseAddressList($s); |
|---|
| 29 | if (PEAR::isError($a) || count($a) != 1) |
|---|
| 30 | return ''; |
|---|
| 31 | $a = $a[0]; |
|---|
| 32 | if ($a->mailbox == '') |
|---|
| 33 | return ''; |
|---|
| 34 | return strtolower($a->mailbox . '@' . $a->host); |
|---|
| 35 | } |
|---|
| 36 | |
|---|
| 37 | function decodeSomeAddresses($s) { |
|---|
| 38 | $a = Mail_RFC822::parseAddressList($s); |
|---|
| 39 | if (PEAR::isError($a)) |
|---|
| 40 | return array(); |
|---|
| 41 | $aa = array(); |
|---|
| 42 | foreach ($a as $v) { |
|---|
| 43 | if ($v->mailbox != '') |
|---|
| 44 | $aa[] = strtolower($v->mailbox . '@' . $v->host); |
|---|
| 45 | } |
|---|
| 46 | return $aa; |
|---|
| 47 | } |
|---|
| 48 | |
|---|
| 49 | //////////////////////////////////////////////////////////////////////////////// |
|---|
| 50 | |
|---|
| 51 | |
|---|
| 52 | // |
|---|
| 53 | // ����ǡ�����߹��ࡣ |
|---|
| 54 | // |
|---|
| 55 | $input = ''; |
|---|
| 56 | $len = ML_EMAIL_MAX_SIZE; |
|---|
| 57 | while (!feof(STDIN) && $len > 0) { |
|---|
| 58 | $s = fread(STDIN, $len); |
|---|
| 59 | $input .= $s; |
|---|
| 60 | $len -= strlen($s); |
|---|
| 61 | unset($s); |
|---|
| 62 | } |
|---|
| 63 | if (!feof(STDIN)) { |
|---|
| 64 | // ����ǡ�������������롣 |
|---|
| 65 | fputs(STDERR, "Mail data size too large.\n"); |
|---|
| 66 | // exit(65); // EX_DATAERR |
|---|
| 67 | exit(0); // XXX Courier�����顼�����夷�Ƥ��ޤ��� |
|---|
| 68 | } |
|---|
| 69 | |
|---|
| 70 | |
|---|
| 71 | // |
|---|
| 72 | // MIME�ǥ����� // |
|---|
| 73 | $decoder = new Mail_mimeDecode($input); |
|---|
| 74 | if (PEAR::isError($decoder)) { |
|---|
| 75 | // MIME�ǥ����ɼ���� |
|---|
| 76 | fputs(STDERR, "Could not decode MIME.\n"); |
|---|
| 77 | // exit(65); // EX_DATAERR |
|---|
| 78 | exit(0); // XXX Courier�����顼�����夷�Ƥ��ޤ��� |
|---|
| 79 | } |
|---|
| 80 | unset($input); |
|---|
| 81 | $given = $decoder->decode( |
|---|
| 82 | array( |
|---|
| 83 | 'include_bodies' => true, |
|---|
| 84 | 'decode_bodies' => true, |
|---|
| 85 | 'decode_headers' => true |
|---|
| 86 | ) |
|---|
| 87 | ); |
|---|
| 88 | unset($decoder); |
|---|
| 89 | |
|---|
| 90 | |
|---|
| 91 | // |
|---|
| 92 | // ���Ԥθ��� // |
|---|
| 93 | |
|---|
| 94 | // ����Ԥ� if (!isset($given->headers['from'])) { |
|---|
| 95 | fputs(STDERR, "No 'from' header found.\n"); |
|---|
| 96 | // exit(65); // EX_DATAERR |
|---|
| 97 | exit(0); // XXX Courier�����顼�����夷�Ƥ��ޤ��� |
|---|
| 98 | } |
|---|
| 99 | $from = decodeSingleAddress($given->headers['from']); |
|---|
| 100 | if ($from == '' || !isset($ML_LIST_SUBSCRIBERS[$from])) { |
|---|
| 101 | // ����Ԥ��桼���ǤϤʤ��� |
|---|
| 102 | fputs(STDERR, "Sender not allowed.\n"); |
|---|
| 103 | // exit(65); // EX_DATAERR |
|---|
| 104 | exit(0); // XXX Courier�����顼�����夷�Ƥ��ޤ��� |
|---|
| 105 | } |
|---|
| 106 | |
|---|
| 107 | // �����XXX isset? |
|---|
| 108 | if (array_search(ML_LIST_ADDRESS, decodeSomeAddresses($given->headers['to'])) === false |
|---|
| 109 | && array_search(ML_LIST_ADDRESS, decodeSomeAddresses($given->headers['cc'])) === false) { |
|---|
| 110 | // �����ML�ǤϤʤ��� |
|---|
| 111 | fputs(STDERR, "Recipient not allowed.\n"); |
|---|
| 112 | // exit(65); // EX_DATAERR |
|---|
| 113 | exit(0); // XXX Courier�����顼�����夷�Ƥ��ޤ��� |
|---|
| 114 | } |
|---|
| 115 | |
|---|
| 116 | |
|---|
| 117 | // |
|---|
| 118 | // ������������� |
|---|
| 119 | // |
|---|
| 120 | $subject = $given->headers['subject']; |
|---|
| 121 | $subject = preg_replace('!^(re(\d+|\[\d+\])?[:>]\s*)+!i', 'Re:', $subject); |
|---|
| 122 | |
|---|
| 123 | |
|---|
| 124 | // |
|---|
| 125 | // �ʸ�ν� |
|---|
| 126 | // |
|---|
| 127 | class ProcessMimeParts { |
|---|
| 128 | var $mime_; |
|---|
| 129 | var $charset_; |
|---|
| 130 | var $text_; |
|---|
| 131 | var $i_; |
|---|
| 132 | |
|---|
| 133 | function ProcessMimeParts($s) { |
|---|
| 134 | $this->mime_ = new Mail_mime(); |
|---|
| 135 | $this->charset_ = ''; |
|---|
| 136 | $this->text_ = $s; |
|---|
| 137 | $this->i_ = 0; |
|---|
| 138 | } |
|---|
| 139 | |
|---|
| 140 | function doit($o) { |
|---|
| 141 | if ($o->ctype_primary == 'multipart') { |
|---|
| 142 | foreach ($o->parts as $oo) |
|---|
| 143 | $this->doit($oo); |
|---|
| 144 | } else |
|---|
| 145 | if ($o->ctype_primary == 'text') { |
|---|
| 146 | if ($o->ctype_secondary == 'plain') { |
|---|
| 147 | if ($this->charset_ != '') |
|---|
| 148 | return; |
|---|
| 149 | if (!isset($o->ctype_parameters['charset'])) |
|---|
| 150 | return; |
|---|
| 151 | $this->charset_ = strtolower($o->ctype_parameters['charset']); |
|---|
| 152 | $this->text_ .= |
|---|
| 153 | mb_convert_encoding($o->body, ML_CHARSET, $this->charset_); |
|---|
| 154 | } |
|---|
| 155 | } else |
|---|
| 156 | if ($o->ctype_primary == 'image') { |
|---|
| 157 | $fn = ''; |
|---|
| 158 | if (isset($o->d_parameters['name'])) |
|---|
| 159 | $fn = $o->d_parameters['name']; |
|---|
| 160 | else |
|---|
| 161 | if (isset($o->d_parameters['filename'])) |
|---|
| 162 | $fn = $o->d_parameters['filename']; |
|---|
| 163 | else |
|---|
| 164 | $fn = sprintf("%d.jpg", $this->i_++); |
|---|
| 165 | $this->mime_->addAttachment( |
|---|
| 166 | $o->body, $o->ctype_primary . '/' . $o->ctype_secondary, |
|---|
| 167 | $fn, false); |
|---|
| 168 | } |
|---|
| 169 | } |
|---|
| 170 | |
|---|
| 171 | function done($subject) { |
|---|
| 172 | if ($this->charset_ == '') { |
|---|
| 173 | fputs(STDERR, "No charset found.\n"); |
|---|
| 174 | // exit(65); // EX_DATAERR |
|---|
| 175 | exit(0); // XXX Courier�����顼�����夷�Ƥ��ޤ��� |
|---|
| 176 | } |
|---|
| 177 | |
|---|
| 178 | $this->mime_->setTXTBody($this->text_); |
|---|
| 179 | $body = $this->mime_->get( |
|---|
| 180 | array( |
|---|
| 181 | 'text_charset' => $charset |
|---|
| 182 | ) |
|---|
| 183 | ); |
|---|
| 184 | |
|---|
| 185 | // PEAR�Х��� // Mail_mime::get()�����Ԥ�;�פˤĤ��롣 |
|---|
| 186 | // SMTP::send()�����Ԥ�;�פ��� |
|---|
| 187 | $body = preg_replace("!\r?\n!", "\r\n", $body); // \r\n��� $body = preg_replace("!\r\n\r\n$!", "", $body); |
|---|
| 188 | |
|---|
| 189 | $headers = $this->mime_->headers( |
|---|
| 190 | array( |
|---|
| 191 | 'From' => ML_LIST_ADDRESS, |
|---|
| 192 | 'To' => ML_LIST_ADDRESS, |
|---|
| 193 | 'Subject' => '=?'.ML_CHARSET.'?B?'.base64_encode($subject).'?=' |
|---|
| 194 | ) |
|---|
| 195 | ); |
|---|
| 196 | |
|---|
| 197 | return array($body, $headers); |
|---|
| 198 | } |
|---|
| 199 | } |
|---|
| 200 | |
|---|
| 201 | $pm = new ProcessMimeParts( |
|---|
| 202 | "[".mb_convert_encoding($ML_LIST_SUBSCRIBERS[$from], ML_CHARSET, ML_CODE_CHARSET)."]\n" |
|---|
| 203 | ); |
|---|
| 204 | |
|---|
| 205 | $pm->doit($given); |
|---|
| 206 | list($body, $headers) = $pm->done($subject); |
|---|
| 207 | unset($pm); |
|---|
| 208 | |
|---|
| 209 | |
|---|
| 210 | // |
|---|
| 211 | // ���������������Ԥ���� |
|---|
| 212 | // |
|---|
| 213 | unset($ML_LIST_SUBSCRIBERS[$from]); |
|---|
| 214 | $dest = array_keys($ML_LIST_SUBSCRIBERS); |
|---|
| 215 | |
|---|
| 216 | |
|---|
| 217 | // |
|---|
| 218 | // �������� |
|---|
| 219 | // |
|---|
| 220 | $mail = Mail::factory('smtp'); // 'mail'���o:�إå������������ |
|---|
| 221 | $o = $mail->send($dest, $headers, $body); |
|---|
| 222 | if ($o !== True) |
|---|
| 223 | fputs(STDERR, $o->toString()); |
|---|
| 224 | |
|---|
| 225 | ?> |
|---|