#! /usr/bin/perl # # grmail.cgi # # 1.005 : 11/22/06 : 送信後のリターンページオプションのバグを修正 # 1.004 : 1/21/06 : Added an option to not display name on To: and From: # 1.003 : 1/15/06 : Added recipient, sender non-display mode # 1.002 : 1/6/06 : Fixed MIME encode # 1.001 : 10/18/05 : Deleted unnecessary spaces in title # 1.0 : 10/17/05 : Initial revision # # Group mail # グループメール # # グループモードとユーザーモードとあります。 # - グループモード # グループモードでは管理人のみメールアドレスを登録することができます。 # 登録されているユーザーはグループパスワードを使ってのみメールを # 送信することができます。 # 登録削除は管理人のみ可能です。 # - ユーザーモード # ユーザーモードではユーザーが自分のメールアドレスを登録することができます。 # 登録の際にはグループパスワードが必要になります。その際個人パスワードを # 設定します。 # メールを送信するときには個人のパスワードが必要になります。 # 登録削除はユーザーが個人のパスワードを使ってすることができます。 # # いずれのモードもメール送信にはパスワードが必要になります。 # # http://www.hidekik.com/ # # Copyright(c) 2005-2006, Hideki Kanayama All rights reserved use strict; use CGI qw(:cgi-lib); use CGI::Carp qw(fatalsToBrowser); use File::Basename; use Jcode; my $lastupdatedyear = 2006; my $version = "1.005"; my $script = basename($0); my $setupfile = "grmail_setup.pl"; my $admindat = "adminpwd.dat"; my $groupdat = "grouppwd.dat"; my $charset = "Shift_JIS"; my $lang = 0; ########################################### our $datafile = "member.dat"; # Title our $title = ('グループメール','Group mail')[$lang]; # Background our $bgimage_en = 0; our $bgimage_file = ''; our $bgcolor = "#ffffff"; # Back link our $backlink_en = 1; our $backlink = '..'; our $backlink_name = '戻る'; # Body width our $body_width = '100'; # col mux of address list our $colmax = 5; # Display admin link our $setup_en = 1; our $setup_name = '管理用'; # Group mode 0:user mode, 1:group mode our $group_mode = 0; # Bcc copoy 0:off, 1:on our $bcc_en = 1; # body_head our $body_head = "

グループメール

"; # body_tail our $body_tail = ' '; # return page after sending a mail # 0: group mail, 1: done page, 2: top page our $return_page = 0; # mail command our $mail_cmd = '/usr/sbin/sendmail -t'; # Recipent, sender non-display mode our $recip_nondisp = 0; our $sender_nondisp = 0; our $sender_dummy = 'dummy@dummy.dum'; # Name on To:, From:, Bcc: # 1: display, 0:no display our $mail_name = 1; # Style Sheet our $style_sheet_en = 0; our $style_sheet = ' '; # Head insert our $head_insert_en = 0; our $head_insert = ' '; our $offset = 9; ####################################### require "$setupfile" if (-e "$setupfile"); my $q = CGI->new; my $cgierror = $q->cgi_error; &error($cgierror) if ($cgierror); my %in = $q->Vars; if (! -e "$admindat"){ if ($in{mode} eq 'wradminpwd'){ &wradminpwd($in{pwd},$admindat); } else { &setadminpwd($admindat); } } if (! -e "$groupdat"){ if ($in{mode} eq 'grwradminpwd'){ &wradminpwd($in{pwd},$groupdat); } else { &setadminpwd($groupdat); } } if ($in{mode} eq 'setmember'){ &setmember; } elsif ($in{mode} eq 'wrmember'){ &wrmember; } elsif ($in{mode} eq 'register_list'){ ®ister_list; } elsif ($in{mode} eq 'register'){ ®ister; } elsif ($in{mode} eq 'delete_list'){ &delete_list; } elsif ($in{mode} eq 'delete_mail'){ &delete_mail; } elsif ($in{mode} eq 'setup'){ &setup; } elsif ($in{mode} eq 'setupwrite'){ &setupwrite; } elsif ($in{mode} eq 'send'){ &send; } else { &mainpage; } sub mainpage { &nomember if (! -e $datafile); my ($maillist,$finnum,$items) = &get_maillist; &htmlhead($title); print $body_head; print "$backlink_name
" if ($backlink_en); print qq(

\n); print qq(\n); print qq(\n); print qq(\n); print qq(\n); print qq(\n\n); my $i; my $j; my $num; for ($i=0;$i<$items;$i+=$colmax){ print qq(\n); $j=0; # $num = $i+$num; while ($j < $colmax){ if ($maillist->[$num]) { if ($maillist->[$num][2] ne 'deleted'){ print qq(\n); $j++; } } else { print qq(\n); $j++; } $num++; } print qq(\n); } print qq(
宛先
\n); print qq(全員\n); print qq(全員解除\n); print qq(
$maillist->[$num][1] 

\n); print qq(送信者
\n); print qq(

\n); if ($group_mode){ print qq(メンバー用パスワードを入力してください
\n); } else { print qq(送信者のパスワードを入力してください
\n); } print qq(

\n); print qq(タイトル\n); print qq(
\n); print qq(

本文\n); print qq(
\n); print qq(

\n); print "$body_tail"; print "

\n"; print "登録 \n"; print "削除 \n"; print "管理用 \n"; print "
\n"; &htmltail; } sub nomember { &htmlhead('メールアドレスが登録されていません'); print qq(

メールアドレスを登録する

\n); print qq(

管理人セットアップ

\n); &htmltail; } sub register_list { &htmlhead('メールアドレス登録'); my $cols; my $adminpwd; my $persopwd1; my $persopwd2; if ($group_mode) { $cols = 3; $adminpwd = "管理人パスワード"; $persopwd1 = ''; $persopwd2 = ''; } else { $cols = 4; $adminpwd = "グループパスワード"; $persopwd1 = "個人パスワード設定"; $persopwd2 = ""; } print < $adminpwd $persopwd1 $persopwd2
名前 メールアドレス

END print qq($titleへ); &htmltail; } sub register { if ($group_mode) { &error('グループモードなので管理人のみ登録できます。') if (!&checkadmin($in{grouppwd})); } else { &error('グループパスワードが違います。') if (!&checkadmin($in{grouppwd},$groupdat)); } my ($data, $finnum) = &get_maillist; $finnum++ if (-e $datafile); my $pwd; if ($group_mode == 0){ $pwd = &makecrypt($in{persopwd}); } open(FILE, ">> $datafile") or &error('$datafileが開けません。'); print FILE "$finnum,$in{name},$in{address},$pwd\n"; close(FILE); print "Location: $script\n\n"; } sub get_maillist { my @data; if (open(FILE, "< $datafile")) { my @detail; my $i=0; my $items; while (){ chomp; @detail = split /,/; $data[$i] = [@detail]; $i++; $items++ if ($detail[2] ne 'deleted'); } close(FILE); my $finnum = $detail[0]; return (\@data,$finnum,$items); } else { return (\@data,0); # return null and final number 0 } } sub send { my $subject = $in{subject}; my $contents = $in{main}; my ($data, $finnum) = &get_maillist; &error("送信者の名前を選択してください。") if ($in{sender} eq 'none'); my $sender_name = $data->[$in{sender}][1]; my $sender_mail = $data->[$in{sender}][2]; my $sender_pwd = $data->[$in{sender}][3]; if ($group_mode){ &error('メンバー用パスワードが違います。') unless (&checkadmin($in{pwd},$groupdat) or &checkadmin($in{pwd},$admindat)); } else { &error('個人用パスワードが違います。') unless (&checkcrypt($in{pwd},$sender_pwd)); } my $i; my @to_mail; foreach $i (0 .. $finnum){ my $item = "m" . "$i"; if ("$in{$item}" eq 'on') { &error('選択されたメールアドレス'."$data->[$i][1]".'が削除されています。') if ($data->[$i][2] eq 'deleted'); my $toaddr = $mail_name ? "$data->[$i][1] <$data->[$i][2]>" : "$data->[$i][2]"; push(@to_mail,"$toaddr"); } } &error('宛先を選択してください。') if ($#to_mail < 0); &error('タイトルと本文は必ず書いてください。') if ($subject eq '' or $contents eq ''); my $to_mail = join ",", @to_mail; $contents = jcode($contents)->jis; my $from_mail; if ($sender_nondisp){ if ($sender_dummy ne '') { $from_mail = $mail_name ? "$sender_name <$sender_dummy>" : "$sender_dummy"; } else { $from_mail = $mail_name ? "$sender_name " : "dummy\@dummy.dum"; } } else { $from_mail = $mail_name ? "$sender_name <$sender_mail>" : "$sender_mail"; } my $header; $header = "To: " . jcode($to_mail)->mime_encode . "\n" if (!$recip_nondisp); $header .= "From: " . jcode("$from_mail")->mime_encode . "\n"; $header .= "Bcc: " if ($bcc_en or $recip_nondisp); $header .= jcode($from_mail)->mime_encode if ($bcc_en); $header .= "," if ($bcc_en and $recip_nondisp); $header .= jcode($to_mail)->mime_encode if ($recip_nondisp); $header .= "\n" if ($bcc_en or $recip_nondisp); $header .= "Subject: " . jcode($subject)->mime_encode . "\n"; $header .= "MIME-Version: 1.0\n"; $header .= "Content-type: text/plain; charset=ISO-2022-JP\n"; $header .= "Content-Transfer-Encoding: 7bit\n\n"; if (open(SMAIL, "| $mail_cmd")){ print SMAIL $header; print SMAIL $contents; close(SMAIL); } else { &error("メールコマンドが実行できません。"); } if ($return_page == 0) { print "Location: $script\n\n"; } elsif ($return_page == 1) { &error("送信しました。

$title $backlink_name"); } else { print "Location: $backlink\n\n"; } } sub delete_list { &htmlhead('メールアドレス削除'); my ($maillist,$finnum) = &get_maillist; print qq(

\n); print qq(
\n); print qq(
\n); if ($group_mode){ print "管理人パスワード"; } else { print "個人パスワード"; } print qq(

); print qq(); print qq(

\n); print qq($titleへ); &htmltail; } sub delete_mail { my ($data, $finnum) = &get_maillist; my $inpwd; if ($group_mode) { &error('グループモードなので管理人のみ削除できます。') unless (&checkadmin($in{pwd})); } else { $inpwd = $data->[$in{delnumber}][3]; &error('個人用パスワードが違います。') unless (&checkcrypt($in{pwd},$inpwd)); } &error("削除する名前を選択してください。") if ($in{delnumber} eq 'none'); open(FILE, "< $datafile") or &error("$datafileが開けません。"); open(TMP, "> tmp.$$"); while (){ my ($i,$name,$email,$pwd) = split /,/; if ($in{delnumber} == $i){ print TMP "$i,$name,deleted\n"; } else { print TMP "$_"; } } close(FILE); close(TMP); rename ("tmp.$$","$datafile"); print "Location: $script\n\n"; } sub checkcrypt { my ($pwd,$encpwd)=@_; return(crypt($pwd,$encpwd) eq "$encpwd" or &checkadmin($pwd)); } sub htmlhead { my $title = shift; my $bgimage; if ($bgimage_en == 1){ $bgimage = "background=\"$bgimage_file\""; } else { $bgimage = "bgcolor=\"$bgcolor\""; } print $q->header(-charset=>$charset); print "\n"; print "\n"; print "\n"; print "$title\n"; if ($head_insert_en == 1){ print "$head_insert\n"; } if ($style_sheet_en == 1){ print "\n"; } if ($in{mode} eq ''){ my ($data, $finnum) = &get_maillist; print qq(\n"; } print "\n"; print "\n"; print "
\n"; } sub copyright { my $mysite = ('http://www.hidekik.com/','http://www.hidekik.com/en/')[$lang]; print "
grmail.cgi Ver. $version
\n"; print "Copyright(C) 2005-$lastupdatedyear, hidekik.com
\n"; } sub htmltail { ©right; print "
\n"; exit; } sub error { my ($msg) = shift; &htmlhead($msg); print "

$msg
\n"; print "
"; print "
"; &htmltail; exit; } sub makecrypt { my $plain = shift; my $salt = join "", ('.', '/', 0..9, 'A'..'Z', 'a'..'z')[rand 64, rand 64]; my $result = crypt($plain,$salt) or crypt($plain,'$1$'.$salt.'$'); return $result; } sub setadminpwd { my $file = shift; &htmlhead('パスワードを入力してください'); print "
\n"; if (! defined $file){ print "
管理者用パスワードを入力してください。
\n"; print "\n"; print "\n"; print "\n"; } else { if ($file eq $admindat) { print "
管理者用パスワードを設定してください。
\n"; print "\n"; } else { print "
グループ用パスワードを設定してください。
\n"; print "\n"; } print "\n"; print "\n"; } print "

"; print "
"; &htmltail; exit; } sub wradminpwd { my $plain = shift; my $file = shift; $file = "$admindat" unless (defined $file); my $passwd = &makecrypt($plain); if (open(FILE,"> $file")){ print FILE "$passwd"; close(FILE); } else { &error('パスワードファイル作成に失敗しました'); } print "Location: $script\n\n"; } sub checkadmin { my $pwd = shift; my $file = shift; $file = "$admindat" unless (defined $file); if (open(FILE,"< $file")){ my $filepwd = ; close(FILE); my $inpwd = crypt($pwd,$filepwd); return ("$inpwd" eq "$filepwd"); } else { &error('パスワードファイルが存在しません'); } } sub setup { my $subname = 'setup'; &setadminpwd if ($in{pwd} eq ''); &error(('管理用パスワードが違います。','Wrong admin password')[$lang]) unless &checkadmin($in{pwd}); &htmlhead($title); my %check; $check{backlink}[$backlink_en] = "checked"; $check{bgimage}[$bgimage_en] = "checked"; $check{setup}[$setup_en] = "checked"; $check{group_mode}[$group_mode] = "checked"; $check{bcc}[$bcc_en] = "checked"; $check{style_sheet}[$style_sheet_en] = "checked"; $check{head_insert}[$head_insert_en] = "checked"; $check{return_page}[$return_page] = "checked"; $check{recip_nondisp}[$recip_nondisp] = "checked"; $check{sender_nondisp}[$sender_nondisp] = "checked"; $check{mail_name}[$mail_name] = "checked"; print "\n"; print "\n"; print "\n"; my $notice = ("
  • セットアップリンクを非表\示にしている場合は、$script?mode=setupからパスワードを入力してこのページに入ってください。
  • 数字やカラー指定は必ず半角で指定してください。全角やブランクだとCGIが起動しなくなります。万一間違って全角で書いてしまった場合は、$setupfileをエディタで開きその場所を半角に正しく修正してください。それで直ります。
  • ", "
  • If you disable to display admin setup link, you can open the page with $script?mode=setup and change the setting.
  • ")[$lang]; print <
      $notice
    END print (('データファイル','data file')[$lang]); print < END print (('バックグランド','background')[$lang]); print < END print (('画像を使う','image')[$lang]); print " "; print (('カラー設定にする','color')[$lang]); print < END print (('画像を使う場合の画像ファイル','image file')[$lang]); print < END print (('カラー設定の場合のカラー番号(白:#ffffff 又は white)','color code(white:white or #ffff)')[$lang]); print < END print (('タイトル名','title')[$lang]); print <
    ブラウザのタイトルバーに表\示されるタイトルです。ページのタイトルは「ページ上部」で自由にタイトル表\示させることができます。 END print (('トップへのリンク','link to top')[$lang]); my $disp = ('表示','display')[$lang]; my $nondisp = ('非表示','not display')[$lang]; my $linkname = ('リンク名','link name')[$lang]; print < $disp $nondisp
    $linkname
    URL
    END print (('表示幅','table width')[$lang]); print " "; print (('ブラウザ全体の','')[$lang]); print <% END print (('宛先表示','Address lines')[$lang]); print " "; print (('一行に表示する宛先の数','number of To: list')[$lang]); print < END print (('セットアップのリンク','link to setup')[$lang]); print < $disp $nondisp
    $linkname
    END my $group = ('グループモード','Group mode')[$lang]; my $user = ('ユーザーモード','User mode')[$lang]; print $group; print < $group $user
    END print (('送信者へのコピー','Copy to sender')[$lang]); my $valid = (('有効','valid')[$lang]); my $invalid = (('無効','invalid')[$lang]); print < $valid $invalid
    END print "送信後の戻りページ"; print < グループメール
    送信完了ページ
    「$backlink_name」ページ END print (('メールコマンド','Mail command')[$lang]); print qq(To:などのヘッダ情報が本文に埋め込まれて送信されるのでsendmailの場合は「sendmail -t」のように-tを必ず付けてください。
    \n); print "\n"; print "\n"; print (('メールヘッダに送信先、送信元メールアドレス表示','Recipient, sender mail address display in a sending mail')[$lang]); print "\n\n"; print (('送信先','Recipient')[$lang]); print <$disp(To:) $nondisp(Bcc:)
    END print (('送信元','Sender')[$lang]); print <$disp $nondisp
    END print (('送信元メールアドレスを非表示にしても送信者の名前はメールヘッダに表示されます。
    ','Even though sender\'s mail address is set as non-display, sender name will be displayed in the header of the mail.
    ')[$lang]); print (('送信元メールアドレスを非表示にする場合From:に付加されるダミーのメールアドレス。','A dummy mail address to be displayed as From: in the header.')[$lang]); print qq(
    \n); print (('これが必要になるので「送信者へのコピー」は効かなくなります。また、プロバイダやメールサーバーにより無効なメールアドレスから送信できない設定になっている場合はメール送信ができません。','\"Copy to sender\" will not work due to this dummy mail address. Some porvider or mail servers do not allow to send a mail from invalid mail address.')[$lang]); print < END print (('To:,From:に名前を表示','Display name on To:, From:')[$lang]); print "\n\n"; print <$disp $nondisp
    END print "\n"; print "\n"; print (('<head>内挿入文','sentense in <head>')[$lang]); print < $valid $invalid
    END print ((' HTML書式
    ポップアップ広告やJavascript、<META>を挿入したい場合にここに記述する。
    以下の記述が<head>〜</head>内に挿入される。
    ','HTML format. Javascript, popup ads, <META> and so on can be inserted in here. ')[$lang]); my $stylesheetname = ('スタイルシート','style sheet')[$lang]; print <$head_insert
    $stylesheetname $valid $invalid

    ページ上部 ページ上部に表\示させるものをHTML表\記

    ページ下部 ページ下部に表\示させるものをHTML表\記

    時間設定 GMTより時間(日本:+9時間) END my $setting = (('設定','setting')[$lang]); print ""; print ""; &htmltail; } sub setupwrite { &error(('管理人パスワードが違います','Wrong admin password')[$lang]) unless ( &checkadmin($in{pwd})); foreach (keys(%in)){ $in{$_} =~ s/\s*$//; } open(SETUP,"> $setupfile"); print SETUP <