#! /usr/bin/perl # # grmob.cgi # # 1.002 : 2/28/08 : 携帯で選択した送信者が正常に選択されないバグを修正 # 1.001 : 2/1/08 : 送信文確認画面モードを追加 # 1.0 : 1/5/08 : Initial revision # # Group mail # 携帯版グループメール # # グループモードとユーザーモードとあります。 # - グループモード # グループモードでは管理人のみメールアドレスを登録することができます。 # 登録されているユーザーはグループパスワードを使ってのみメールを # 送信することができます。 # 登録削除は管理人のみ可能です。 # - ユーザーモード # ユーザーモードではユーザーが自分のメールアドレスを登録することができます。 # 登録の際にはグループパスワードが必要になります。その際個人パスワードを # 設定します。 # メールを送信するときには個人のパスワードが必要になります。 # 登録削除はユーザーが個人のパスワードを使ってすることができます。 # # いずれのモードもメール送信にはパスワードが必要になります。 # # http://www.hidekik.com/ # # Copyright(c) 2005-2008, Hideki Kanayama All rights reserved use strict; use CGI qw(:cgi-lib); use CGI::Carp qw(fatalsToBrowser); use File::Basename; use Jcode; my $lastupdatedyear = 2008; my $version = "1.002"; my $script = basename($0); my $setupfile = "grmob_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]; # Back link our $backlink_en = 1; our $backlink = '..'; our $backlink_name = '戻る'; # 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; # Confirmation 0:off, 1:on our $confirm_en = 0; # 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; ####################################### 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 '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; } elsif ($in{mode} eq 'confirm'){ &confirm; } elsif ($in{mode} eq 'next'){ &nextaction; } else { &mainpage; } sub mainpage { &nomember if (! -e $datafile); my ($maillist,$finnum,$items) = &get_maillist; &htmlhead($title); print "$backlink_name
" if ($backlink_en); # print qq(
\n); print qq(\n); if ($confirm_en){ print qq(\n); } else { print qq(\n); } print qq(宛先
\n); my $i; my $j; my $num; for ($num=0;$num<=$finnum;$num++){ if ($maillist->[$num][2] ne 'deleted'){ my $checked; if ($in{"m$num"} eq 'on') { $checked = 'checked'; } else { $checked = ''; } 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); $in{main} =~ s/
/\n/ig; print qq(
\n); print qq(

\n); print "登録 \n"; print "削除 \n"; print "管理用 \n"; &htmltail; } sub confirm { my ($maillist, $finnum, $items) = &formcheck; &htmlhead('メール確認'); print 'メール確認画面

'; print qq(\n); print "To:"; my @tolist; foreach my $mm (@$maillist){ my $mnum = "m$mm->[0]"; if ("$in{$mnum}" eq 'on'){ push (@tolist, "$mm->[1]"); print qq(\n); } } print join ',', @tolist; print "
\n"; print "From: $maillist->[$in{sender}][1]
\n"; print qq(\n); print "Subject: $in{subject}
\n"; print "-----
\n"; my $main = $in{main}; $in{main} =~ s/\r\n/
/g; $in{main} =~ s/\r/
/g; $in{main} =~ s/\n/
/g; print "$in{main}

\n"; print qq( \n); print qq(\n); print qq(\n); print qq(\n); print qq(\n); print qq(\n); print qq(

\n); &htmltail; } sub nextaction { if ($in{send} ne ''){ &send; } else { &mainpage; } } sub nomember { &htmlhead('メールアドレスが登録されていません'); print qq(

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

\n); print qq(

管理人セットアップ

\n); &htmltail; } sub register_list { &htmlhead('メールアドレス登録'); my $adminpwd; my $persopwd1; my $persopwd2; if ($group_mode) { $adminpwd = "管理人パスワード"; $persopwd1 = ''; $persopwd2 = ''; } else { $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 formcheck { my ($data, $finnum) = &get_maillist; &error("送信者の名前を選択してください。") if ($in{sender} eq 'none'); 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)); } return ($data, $finnum); } sub send { my ($data, $finnum) = &formcheck; my $subject = $in{subject}; my $contents = $in{main}; my $sender_name = $data->[$in{sender}][1]; my $sender_mail = $data->[$in{sender}][2]; 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; print $q->header(-charset=>$charset); print "\n"; print "\n"; print "\n"; print "$title\n"; print "\n"; print "\n"; } sub copyright { my $mysite = ('http://www.hidekik.com/','http://www.hidekik.com/en/')[$lang]; print "


grmob.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"; &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{setup}[$setup_en] = "checked"; $check{group_mode}[$group_mode] = "checked"; $check{bcc}[$bcc_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"; $check{confirm}[$confirm_en] = "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 < #END print (('データファイル
    ','data file')[$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 (('セットアップのリンク
    ','link to setup')[$lang]); print <$disp $nondisp
    $linkname
    END my $group = ('グループモード','Group mode')[$lang]; my $user = ('ユーザーモード','User mode')[$lang]; print "$group
    \n"; print <$group $user
    END print (('送信者へのコピー
    ','Copy to sender')[$lang]); my $valid = (('有効','valid')[$lang]); my $invalid = (('無効','invalid')[$lang]); print <$valid $invalid
    送信前の確認画面
    $valid $invalid
    送信後の戻りページ
    グループメール
    送信完了ページ
    「$backlink_name」ページ
    END print (('メールコマンド
    ','Mail command')[$lang]); print qq(To:などのヘッダ情報が本文に埋め込まれて送信されるのでsendmailの場合は「sendmail -t」のように-tを必ず付けてください。

    \n); print (('メールヘッダに送信先、送信元メールアドレス表示
    ','Recipient, sender mail address display in a sending mail')[$lang]); 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 (('To:,From:に名前を表示
    ','Display name on To:, From:')[$lang]); print <$disp $nondisp
    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 <