| 1 | #!/usr/bin/perl |
1 | #!/usr/local/bin/perl |
| 2 | |
2 | |
| 3 | ## This file is profSendMail.pl |
3 | ## This file is profSendMail.pl |
| 4 | ## It provides a utility for professors to send mail to one or more students |
4 | ## It provides a utility for professors to send mail to one or more students |
| 5 | ## using individualized emails or mass emails |
5 | ## using individualized emails or mass emails |
|
|
6 | ## Original by the WebWork Team at University of Rochester |
|
|
7 | ## Modifications for Invalid Address Checking and for CC's |
|
|
8 | ## by Jonathan Duncan and William Wheeler at Indiana University |
| 6 | |
9 | |
| 7 | use lib '/ww/webwork/development/'; # mainWeBWorKDirectory; |
10 | use lib '/ww/webwork/gage_system/webwork/system/lib/'; # mainWeBWorKDirectory |
| 8 | |
11 | |
| 9 | use Global; |
12 | use Global; |
| 10 | use CGI qw(:standard); |
13 | use CGI qw(:standard); |
| 11 | use Auth; |
14 | use Auth; |
| 12 | use Net::SMTP; |
15 | use Net::SMTP; |
| … | |
… | |
| 25 | my $course = $cgi->param('course'); |
28 | my $course = $cgi->param('course'); |
| 26 | my $user = $cgi->param('user'); |
29 | my $user = $cgi->param('user'); |
| 27 | my $session_key = $cgi->param('key'); |
30 | my $session_key = $cgi->param('key'); |
| 28 | my $openfilename = $cgi->param('openfilename'); |
31 | my $openfilename = $cgi->param('openfilename'); |
| 29 | |
32 | |
|
|
33 | #is this necessary? |
|
|
34 | unless ($course && $user && $session_key) |
|
|
35 | {&wwerror("$0","The script did not receive the proper input data.","","", "");} |
|
|
36 | |
| 30 | &Global::getCourseEnvironment($course); |
37 | &Global::getCourseEnvironment($course); |
| 31 | |
38 | |
| 32 | my $scriptDirectory = $Global::scriptDirectory; |
39 | my $scriptDirectory = $Global::scriptDirectory; |
| 33 | my $databaseDirectory = $Global::databaseDirectory; |
40 | my $databaseDirectory = $Global::databaseDirectory; |
| 34 | my $htmlURL = $Global::htmlURL; |
41 | my $htmlURL = $Global::htmlURL; |
| 35 | my $cgiURL = $Global::cgiWebworkURL; |
42 | my $cgiURL = $Global::cgiWebworkURL; |
| 36 | my $courseScriptsDirectory = $Global::courseScriptsDirectory; |
43 | my $courseScriptsDirectory = $Global::courseScriptsDirectory; |
| 37 | my $templateDirectory = getCourseTemplateDirectory; |
44 | my $templateDirectory = getCourseTemplateDirectory; |
| 38 | my $emailDirectory = getCourseEmailDirectory; |
45 | my $emailDirectory = getCourseEmailDirectory; |
| 39 | my $scoringDirectory = getCourseScoringDirectory; |
46 | my $scoringDirectory = getCourseScoringDirectory; |
| 40 | my $feedbackAddress = $Global::feedbackAddress; |
47 | my $feedbackAddress = $Global::feedbackAddress; |
| 41 | my $defaultClasslistFile = getCourseClasslistFile($course); |
48 | my $defaultClasslistFile = getCourseClasslistFile($course); |
| 42 | my $default_msg = 'default.msg'; |
49 | my $default_msg = 'default.msg'; |
| 43 | my $old_default_msg = 'default_old.msg'; |
50 | my $old_default_msg = 'default_old.msg'; |
|
|
51 | |
| 44 | require "${scriptDirectory}$Global::FILE_pl"; |
52 | require "${scriptDirectory}$Global::FILE_pl"; |
| 45 | |
|
|
| 46 | require "${scriptDirectory}$Global::classlist_DBglue_pl"; |
53 | require "${scriptDirectory}$Global::classlist_DBglue_pl"; |
| 47 | require "${scriptDirectory}$Global::HTMLglue_pl"; |
54 | require "${scriptDirectory}$Global::HTMLglue_pl"; |
| 48 | require "${scriptDirectory}$Global::FILE_pl"; |
55 | require "${scriptDirectory}$Global::FILE_pl"; |
| 49 | |
56 | |
| 50 | # log access |
57 | # log access |
| 51 | &Global::log_info('', query_string); |
58 | &Global::log_info('', query_string); |
| 52 | |
59 | |
| 53 | my $permissionsFile = &Global::getCoursePermissionsFile($course); |
60 | my $permissionsFile = &Global::getCoursePermissionsFile($course); |
| 54 | my $permissions = &get_permissions($user, $permissionsFile); |
61 | my $permissions = &get_permissions($user, $permissionsFile); |
| 55 | my $keyFile = &Global::getCourseKeyFile($course); |
62 | my $keyFile = &Global::getCourseKeyFile($course); |
| 56 | |
63 | |
| 57 | |
64 | |
| 58 | #verify session key |
65 | #verify session key |
| 59 | &verify_key($user, $session_key, "$keyFile", $course); |
66 | &verify_key($user, $session_key, "$keyFile", $course); |
| 60 | |
67 | |
| 61 | #verify permissions are correct |
68 | #verify permissions are correct |
| 62 | if (($permissions != $Global::instructor_permissions) and ($permissions != $Global::TA_permissions) ) { |
69 | if( ($permissions != $Global::instructor_permissions) and ($permissions != $Global::TA_permissions) ) { |
| 63 | print "permissions = $permissions instructor_permissions = $Global::instructor_permissions\n"; |
70 | print "permissions = $permissions instructor_permissions = $Global::instructor_permissions\n"; |
| 64 | print &html_NO_PERMISSION; |
71 | print &html_NO_PERMISSION; |
| 65 | exit(0); |
72 | exit(0); |
| 66 | } |
73 | } |
| 67 | |
74 | |
| 68 | #user macros that can be used in the email message |
75 | #user macros that can be used in the email message |
| 69 | my $SID = ''; |
76 | my $SID = ''; |
| 70 | my $FN = ''; |
77 | my $FN = ''; |
| 71 | my $LN = ''; |
78 | my $LN = ''; |
| … | |
… | |
| 103 | $availableStudents_ref = getAllLoginNamesSortedByName(); |
110 | $availableStudents_ref = getAllLoginNamesSortedByName(); |
| 104 | } |
111 | } |
| 105 | |
112 | |
| 106 | my @availableStudents = @$availableStudents_ref; |
113 | my @availableStudents = @$availableStudents_ref; |
| 107 | |
114 | |
| 108 | #my %loginName_StudentID_Hash = %{getLoginName_StudentID_Hash()}; |
115 | #my %loginName_StudentID_Hash = %{getLoginName_StudentID_Hash()}; |
| 109 | my %studentID_LoginName_Hash = %{getStudentID_LoginName_Hash()}; |
116 | my %studentID_LoginName_Hash = %{getStudentID_LoginName_Hash()}; |
| 110 | |
|
|
| 111 | |
117 | |
| 112 | |
118 | |
| 113 | #make sure message file was submitted and exists |
119 | #make sure message file was submitted and exists |
| 114 | my $messageFileName; |
120 | my $messageFileName; |
| 115 | if (defined($openfilename) && -e "${emailDirectory}$openfilename") { |
121 | if (defined($openfilename) && -e "${emailDirectory}$openfilename") { |
| 116 | if ( -R "${emailDirectory}$openfilename") { |
122 | if ( -R "${emailDirectory}$openfilename") { |
| 117 | $messageFileName = $openfilename; |
123 | $messageFileName = $openfilename; |
|
|
124 | } |
| 118 | } else { |
125 | else { |
| 119 | wwerror ('File is not readable', "The file |
126 | wwerror ('File is not readable', "The file |
| 120 | ${emailDirectory}$openfilename |
127 | ${emailDirectory}$openfilename |
| 121 | is not readable by the webserver. Check that it's permissions are set correctly."); |
128 | is not readable by the webserver. Check that its permissions are set correctly."); |
| 122 | } |
129 | } |
|
|
130 | } |
| 123 | } else { |
131 | else { |
| 124 | $messageFileName = $default_msg; |
132 | $messageFileName = $default_msg; |
| 125 | } |
133 | } |
| 126 | |
134 | |
| 127 | |
135 | |
| 128 | #get row and column info if submitted |
136 | #get row and column info if submitted |
| 129 | my $rows = (defined($cgi->param('rows'))) ? $cgi->param('rows') : $Global::editor_window_rows; |
137 | my $rows = (defined($cgi->param('rows'))) ? $cgi->param('rows') : $Global::editor_window_rows; |
| 130 | my $columns = (defined($cgi->param('columns'))) ? $cgi->param('columns') : $Global::editor_window_columns; |
138 | my $columns = (defined($cgi->param('columns'))) ? $cgi->param('columns') : $Global::editor_window_columns; |
| 131 | |
139 | |
| 132 | #Deal with filled out forms and various actions resulting from different buttons |
140 | #Deal with filled out forms and various actions resulting from different buttons |
| 133 | if ( defined($cgi->param('action')) ) { |
141 | if ( defined( $cgi->param('action') ) ) { |
| 134 | if (defined($cgi->param('savefilename'))) { |
142 | if( defined( $cgi->param('savefilename') ) and ( $cgi->param('savefilename') =~ /^[~.]/ || $cgi->param('savefilename') =~ /\.\./ ) ) { |
| 135 | &user_error("For security reasons, you cannot save a message in any directory higher than the email directory. Please specify a file name to save under.") if ($cgi->param('savefilename') =~ /^[~.]/ || $cgi->param('savefilename') =~ /\.\./); |
143 | &user_error("For security reasons, you cannot save a message in any directory higher than the email directory. Please specify a file name to save under."); |
| 136 | } |
144 | } |
| 137 | |
145 | |
|
|
146 | #do nothing, but needed to prevent an infinite loop |
|
|
147 | if($cgi->param('action') eq 'Cancel' ) { } |
| 138 | #if Save button was clicked |
148 | #if Save button was clicked |
| 139 | if (( $cgi->param('action') eq 'Save') && defined($cgi->param('body')) && defined($cgi->param('savefilename'))) { |
149 | elsif( ( $cgi->param('action') eq 'Save') && defined( $cgi->param('body') ) && defined( $cgi->param('savefilename') ) ) { |
| 140 | |
|
|
| 141 | my $temp_body = $cgi->param('body'); |
150 | my $temp_body = $cgi->param('body'); |
| 142 | $temp_body =~ s/\r\n/\n/g; |
151 | $temp_body =~ s/\r\n/\n/g; |
| 143 | $temp_body = "From: " . $cgi->param('from') . "\n" . |
152 | $temp_body = "From: " . $cgi->param('from') . "\n" . |
|
|
153 | "Reply-To: " . $cgi->param('replyTo') . "\n" . |
|
|
154 | "Cc: " . $cgi->param('cc') . "\n" . |
|
|
155 | "Subject: " . $cgi->param('subject') . "\n" . |
|
|
156 | "Message: \n" . $temp_body; |
|
|
157 | |
|
|
158 | saveProblem($temp_body, $cgi->param('savefilename')); |
|
|
159 | $messageFileName = $cgi->param('savefilename'); |
|
|
160 | } |
|
|
161 | #if Save As button was clicked |
|
|
162 | elsif( ( $cgi->param('action') eq 'Save as' ) && defined( $cgi->param('body') ) && defined( $cgi->param('savefilename') ) ) { |
|
|
163 | $messageFileName = $cgi->param('savefilename'); |
|
|
164 | |
|
|
165 | if ($messageFileName =~ /^[~.]/ || $messageFileName =~ /\.\./) { |
|
|
166 | &user_error("For security reasons, you cannot specify a merge file from a directory higher than the email directory (you can't use ../blah/blah). Please specify a different file or move the needed file to the email directory"); |
|
|
167 | } |
|
|
168 | |
|
|
169 | my $temp_body = $cgi->param('body'); |
|
|
170 | $temp_body =~ s/\r\n/\n/g; |
|
|
171 | $temp_body = "From: " . $cgi->param('from') . "\n" . |
| 144 | "Reply-To: " . $cgi->param('replyTo') . "\n" . |
172 | "Reply-To: " . $cgi->param('replyTo') . "\n" . |
|
|
173 | "Cc: " . $cgi->param('cc') . "\n" . |
| 145 | "Subject: " . $cgi->param('subject') . "\n" . |
174 | "Subject: " . $cgi->param('subject') . "\n" . |
| 146 | "Message: \n" . $temp_body; |
175 | "Message: \n" . $temp_body; |
| 147 | |
176 | |
| 148 | saveProblem($temp_body, $cgi->param('savefilename')); |
|
|
| 149 | $messageFileName = $cgi->param('savefilename'); |
|
|
| 150 | |
|
|
| 151 | #if Save As button was clicked |
|
|
| 152 | } elsif (( $cgi->param('action') eq 'Save as') && defined($cgi->param('body')) && defined($cgi->param('savefilename'))) { |
|
|
| 153 | |
|
|
| 154 | $messageFileName = $cgi->param('savefilename'); |
|
|
| 155 | |
|
|
| 156 | if ($messageFileName =~ /^[~.]/ || $messageFileName =~ /\.\./) { |
|
|
| 157 | &user_error("For security reasons, you cannot specify a merge file from a directory higher than the email directory (you can't use ../blah/blah). Please specify a different file or move the needed file to the email directory"); |
|
|
| 158 | } |
|
|
| 159 | |
|
|
| 160 | |
|
|
| 161 | my $temp_body = $cgi->param('body'); |
|
|
| 162 | $temp_body =~ s/\r\n/\n/g; |
|
|
| 163 | $temp_body = "From: " . $cgi->param('from') . "\n" . |
|
|
| 164 | "Reply-To: " . $cgi->param('replyTo') . "\n" . |
|
|
| 165 | "Subject: " . $cgi->param('subject') . "\n" . |
|
|
| 166 | "Message: \n" . $temp_body; |
|
|
| 167 | |
|
|
| 168 | saveNewProblem($temp_body, $messageFileName); |
177 | saveNewProblem($temp_body, $messageFileName); |
| 169 | |
178 | } |
| 170 | #if Save As Default button was clicked |
179 | #if Save As Default button was clicked |
| 171 | } elsif (( $cgi->param('action') eq 'Save as Default') && defined($cgi->param('body'))) { |
180 | elsif( ( $cgi->param('action') eq 'Save as Default' ) && defined( $cgi->param('body') ) ) { |
| 172 | |
|
|
| 173 | my $temp_body; |
181 | my $temp_body; |
| 174 | $temp_body = $cgi->param('body'); |
182 | $temp_body = $cgi->param('body'); |
| 175 | $temp_body =~ s/\r\n/\n/g; |
183 | $temp_body =~ s/\r\n/\n/g; |
| 176 | |
184 | |
| 177 | #get default.msg and back it up in default.old.msg |
185 | #get default.msg and back it up in default.old.msg |
| 178 | open DEFAULT, "$emailDirectory$default_msg"; |
186 | open DEFAULT, "$emailDirectory$default_msg"; |
| 179 | $temp_body = <DEFAULT>; |
187 | $temp_body = <DEFAULT>; |
| 180 | close DEFAULT; |
188 | close DEFAULT; |
| 181 | |
189 | |
| 182 | if ( -e "$emailDirectory$old_default_msg") { |
190 | if ( -e "$emailDirectory$old_default_msg") { |
| 183 | saveProblem($temp_body, $old_default_msg); |
191 | saveProblem($temp_body, $old_default_msg); |
|
|
192 | } |
| 184 | } else { |
193 | else { |
| 185 | saveNewProblem($temp_body, $old_default_msg); |
194 | saveNewProblem($temp_body, $old_default_msg); |
| 186 | } |
195 | } |
| 187 | |
196 | |
| 188 | #save new default message as default.msg |
197 | #save new default message as default.msg |
| 189 | $temp_body = $cgi->param('body'); |
198 | $temp_body = $cgi->param('body'); |
| 190 | $temp_body =~ s/\r\n/\n/g; |
199 | $temp_body =~ s/\r\n/\n/g; |
| 191 | $temp_body = "From: " . $cgi->param('from') . "\n" . |
200 | $temp_body = "From: " . $cgi->param('from') . "\n" . |
| 192 | "Reply-To: " . $cgi->param('replyTo') . "\n" . |
201 | "Reply-To: " . $cgi->param('replyTo') . "\n" . |
|
|
202 | "Cc: " . $cgi->param('cc') . "\n" . |
| 193 | "Subject: " . $cgi->param('subject') . "\n" . |
203 | "Subject: " . $cgi->param('subject') . "\n" . |
| 194 | "Message: \n" . $temp_body; |
204 | "Message: \n" . $temp_body; |
| 195 | |
205 | |
| 196 | saveProblem($temp_body, $default_msg); |
206 | saveProblem($temp_body, $default_msg); |
| 197 | $messageFileName = $default_msg; |
207 | $messageFileName = $default_msg; |
| 198 | |
208 | } |
| 199 | #if Send Email button was clicked |
209 | #if Send Email button was clicked, check addresses |
|
|
210 | elsif( ( $cgi->param('action') eq 'Send Email' ) || ( $cgi->param('action') eq 'Send to Good Addresses' ) ) { |
|
|
211 | |
|
|
212 | my $cc; |
|
|
213 | |
| 200 | } elsif ( $cgi->param('action') eq 'Send Email' ) { |
214 | if( ($cgi->param('action')) eq 'Send Email' ) { |
|
|
215 | # define our local procedure variables |
|
|
216 | my @Address = (); |
|
|
217 | my @Name = (); |
|
|
218 | my @BadAddress = (); |
| 201 | |
219 | |
| 202 | my @studentID = (); |
220 | # get list of addresses to verify from class list |
| 203 | |
|
|
| 204 | if ($cgi->param('To') eq 'classList' && defined($cgi->param('classList')) && $cgi->param('classList') ne 'None') { |
221 | if( $cgi->param('To') eq 'classList' && defined( $cgi->param('classList') ) && $cgi->param('classList') ne 'None' ) { |
|
|
222 | |
| 205 | my $classlist = $cgi->param('classList'); |
223 | my $classlist = $cgi->param('classList'); |
| 206 | my $classListFile = "$templateDirectory$classlist"; |
224 | my $classListFile = "$templateDirectory$classlist"; |
| 207 | my @classList = (); |
225 | my @classList = (); |
| 208 | checkClasslistFile($Global::noOfFieldsInClasslist,$classListFile); |
226 | checkClasslistFile($Global::noOfFieldsInClasslist,$classListFile); |
| 209 | open(FILE, "$classListFile") || die "can't open $classListFile"; |
227 | open(FILE, "$classListFile") || die "can't open $classListFile"; |
| 210 | @classList=<FILE>; |
228 | @classList=<FILE>; |
| 211 | close(FILE); |
229 | close(FILE); |
| 212 | |
230 | |
| 213 | foreach (@classList) { ## read through classlist and send e-mail |
231 | foreach( @classList ) { # read through classlist, getting email and name of all active students |
| 214 | ## message to all active students |
|
|
| 215 | unless ($_ =~ /\S/) {next;} ## skip blank lines |
232 | next unless ($_ =~ /\S/); ## skip blank lines |
| 216 | chomp; |
233 | chomp; |
|
|
234 | |
| 217 | my @classListRecord=&getRecord($_); |
235 | my @classListRecord = &getRecord($_); |
| 218 | my ($studentID, $lastName, $firstName, $status, $comment, $section, $recitation, $email_address, $login_name) |
236 | my ($studentID, $lastName, $firstName, $status, $comment, $section, $recitation, $email_address, $login_name) |
| 219 | = @classListRecord; |
237 | = @classListRecord; |
| 220 | unless (&dropStatus($status)) { |
238 | unless( &dropStatus($status) || $login_name =~ /^$Global::practiceUser/ ) { |
| 221 | push (@studentID, $studentID); |
239 | push(@Address,$email_address); |
| 222 | $fn{$studentID} = $firstName; |
240 | push(@Name,$firstName . ' ' . $lastName); |
| 223 | $ln{$studentID} = $lastName; |
|
|
| 224 | $section{$studentID} = $section; |
|
|
| 225 | $recitation{$studentID} = $recitation; |
|
|
| 226 | $status{$studentID} = $status; |
|
|
| 227 | $email{$studentID} = $email_address; |
|
|
| 228 | $login{$studentID} = $login_name; |
|
|
| 229 | } |
|
|
| 230 | } |
241 | } |
|
|
242 | } # end foreach |
| 231 | } |
243 | } |
|
|
244 | # get list of addresses to verify from selected list |
| 232 | elsif ($cgi->param('To') eq 'studentID' && defined($cgi->param('studentID'))) { |
245 | elsif( $cgi->param('To') eq 'studentID' && defined( $cgi->param('studentID') ) ) { |
| 233 | @studentID = $cgi->param('studentID'); |
246 | my(@studentID) = $cgi->param('studentID'); |
| 234 | my ($studentID, $login_name); |
247 | my($studentID, $login_name); |
| 235 | |
248 | |
| 236 | foreach $studentID (@studentID) { |
249 | foreach $studentID (@studentID) { |
| 237 | $login_name = $studentID_LoginName_Hash{$studentID}; |
250 | $login_name = $studentID_LoginName_Hash{$studentID}; |
| 238 | &attachCLRecord($login_name); |
251 | &attachCLRecord($login_name); |
| 239 | $fn{$studentID} = CL_getStudentFirstName($login_name); |
252 | push(@Address, CL_getStudentEmailAddress($login_name)); |
| 240 | $ln{$studentID} = CL_getStudentLastName($login_name); |
253 | push(@Name, CL_getStudentFirstName($login_name) . ' ' . CL_getStudentLastName($login_name)); |
| 241 | $section{$studentID} = CL_getClassSection($login_name); |
|
|
| 242 | $recitation{$studentID} = CL_getClassRecitation($login_name); |
|
|
| 243 | $status{$studentID} = CL_getStudentStatus($login_name); |
|
|
| 244 | $email{$studentID} = CL_getStudentEmailAddress($login_name); |
|
|
| 245 | $login{$studentID} = $login_name; |
|
|
| 246 | } |
254 | } |
| 247 | |
|
|
| 248 | } |
255 | } |
|
|
256 | # get list of addresses to verify from all students |
| 249 | elsif ($cgi->param('To') eq 'all_students') { |
257 | elsif ($cgi->param('To') eq 'all_students') { |
| 250 | @studentID = (); |
258 | my(@studentID) = (); |
| 251 | my ($studentID, $login_name, $status); |
259 | my($studentID, $login_name, $status); |
| 252 | |
260 | |
| 253 | foreach $login_name (@availableStudents) { |
261 | foreach $login_name (@availableStudents) { |
| 254 | &attachCLRecord($login_name); |
262 | &attachCLRecord($login_name); |
| 255 | $status = CL_getStudentStatus($login_name); |
263 | $status = CL_getStudentStatus($login_name); |
| 256 | next if &dropStatus($status); |
264 | next if( &dropStatus($status) || $login_name =~ /^$Global::practiceUser/ ); |
| 257 | $studentID = CL_getStudentID($login_name); |
265 | |
| 258 | push(@studentID,$studentID); |
266 | push(@Address, CL_getStudentEmailAddress($login_name)); |
| 259 | |
267 | push(@Name, CL_getStudentFirstName($login_name) . ' ' . CL_getStudentLastName($login_name)); |
| 260 | $fn{$studentID} = CL_getStudentFirstName($login_name); |
|
|
| 261 | $ln{$studentID} = CL_getStudentLastName($login_name); |
|
|
| 262 | $section{$studentID} = CL_getClassSection($login_name); |
|
|
| 263 | $recitation{$studentID} = CL_getClassRecitation($login_name); |
|
|
| 264 | $status{$studentID} = CL_getStudentStatus($login_name); |
|
|
| 265 | $email{$studentID} = CL_getStudentEmailAddress($login_name); |
|
|
| 266 | $login{$studentID} = $login_name; |
|
|
| 267 | } |
268 | } |
| 268 | } |
269 | } |
|
|
270 | # no list of addresses to verify! |
| 269 | else { |
271 | else { |
| 270 | &user_error('You didn\'t select any recipients. Make sure you select either all student in the course, individual students or a whole classlist.'); |
272 | &user_error('You didn\'t select any recipients. Make sure you select either all student in the course, individual students or a whole classlist.'); |
| 271 | } |
273 | } |
| 272 | |
274 | |
| 273 | my $mergeFile = ''; |
275 | # now actually verify the addresses, storing bad name+addresses in @BadAddress |
| 274 | |
276 | |
| 275 | #the radio button named 'merge' determines whether to take the selected mergefile |
277 | $cc = $cgi->param('cc'); |
| 276 | #or one that was typed in. A error message is given if select one and use the other |
278 | push( @Address, $cc ) if defined($cc) and $cc; |
| 277 | $mergeFile = $scoringDirectory . $cgi->param('mergeFiles') |
|
|
| 278 | if ($cgi->param('merge') eq 'mergeFiles' && defined($cgi->param('mergeFiles')) && $cgi->param('mergeFiles') ne 'None'); |
|
|
| 279 | |
|
|
| 280 | $mergeFile = $templateDirectory . $cgi->param('mergeFile') |
|
|
| 281 | if ($cgi->param('merge') eq 'mergeFile' && defined($cgi->param('mergeFile')) && $cgi->param('mergeFile') !~ m|/$|); #does not end in a / |
|
|
| 282 | |
|
|
| 283 | if ($mergeFile =~ /^[~.]/ || $mergeFile =~ /\.\./) { |
|
|
| 284 | &user_error("For security reasons, you cannot specify a merge file from a directory higher than the email directory. Please specify a different file or move the needed file to the email directory"); |
|
|
| 285 | } |
279 | |
| 286 | if ($cgi->param('body') =~ /(\$COL\[.*?\])/ && !(-e $mergeFile)) { |
280 | my $i; |
| 287 | &user_error("In order to use the \$COL[] you must specify a merge file. The file you specified does not exist. Also, make sure you selected the right checkbox."); |
281 | my $smtp = Net::SMTP -> new( $Global::smtpServer, Timeout=>10 ) || &internal_error( "Couldn't contact SMTP server." ); |
|
|
282 | $smtp -> mail($Global::webmaster); |
| 288 | } |
283 | |
| 289 | |
284 | for( $i = 0; $i < @Address; $i++ ) { |
| 290 | |
285 | if( ! $smtp -> recipient( $Address[$i] ) ) { # this one is bad...put it in the list |
| 291 | my %mergeAArray = (); |
286 | $Address[$i] = 'none' if ( ! $Address[$i] ); |
| 292 | unless ($mergeFile eq '') {%mergeAArray = &delim2aa($mergeFile);} |
287 | push( @BadAddress, $Name[$i] . ' (' . $Address[$i] . ')' ); |
| 293 | |
|
|
| 294 | foreach my $studentID (@studentID) { |
|
|
| 295 | unless ((defined $mergeAArray{$studentID}) or ($mergeFile eq '')) { |
|
|
| 296 | next if $cgi->param('no_record'); |
|
|
| 297 | } |
|
|
| 298 | @COL =(); |
|
|
| 299 | $SID = $studentID; |
|
|
| 300 | $LN = defined $ln{$studentID} ? $ln{$studentID} :''; |
|
|
| 301 | $FN = defined $fn{$studentID} ? $fn{$studentID} :''; |
|
|
| 302 | $SECTION = defined $section{$studentID} ? $section{$studentID} :''; |
|
|
| 303 | $RECITATION = defined $recitation{$studentID} ? $recitation{$studentID} :''; |
|
|
| 304 | $EMAIL = defined $email{$studentID} ? $email{$studentID} :''; |
|
|
| 305 | $STATUS =defined $status{$studentID} ? $status{$studentID} :''; |
|
|
| 306 | $LOGIN = $login{$studentID}; |
|
|
| 307 | |
|
|
| 308 | my ($dbString, @dbArray); |
|
|
| 309 | if (defined $mergeAArray{$SID}) { |
|
|
| 310 | $dbString = $mergeAArray{$SID}; ## get sid record from merge file |
|
|
| 311 | @dbArray = &getRecord($dbString); |
|
|
| 312 | unshift(@dbArray,$SID); |
|
|
| 313 | unshift(@dbArray,""); ## note COL[1] is the first column |
|
|
| 314 | @COL= @dbArray; ## put merge fields in COL array |
|
|
| 315 | $endCol = @COL; ## \endCol-1 gives last field, etc |
|
|
| 316 | } |
288 | } |
|
|
289 | } |
|
|
290 | |
|
|
291 | $smtp -> reset(); |
|
|
292 | $smtp -> quit(); |
|
|
293 | |
|
|
294 | # if we had any BadAddress entries, complain |
|
|
295 | if( @BadAddress > 0 ) { |
|
|
296 | # Begin Page with a header |
|
|
297 | print &htmlTOP( "Send Mail for " . $course ), |
|
|
298 | $cgi -> a( { -href=>"${cgiURL}profLogin.pl?user=$user&key=$session_key&course=$course" }, |
|
|
299 | $cgi -> img( { -name=>'upImg', -src=>"${Global::upImgUrl}", -align=>'right', -border=>'1', -alt=>'[Up]'} ) ), |
|
|
300 | $cgi -> p; |
| 317 | |
301 | |
|
|
302 | # Page title |
|
|
303 | print "\n",$cgi->hr, $cgi->br,"\n\n", |
|
|
304 | $cgi -> h3( { -align=>'left' }, "Error Sending Mail for $course" ), "\n", |
|
|
305 | $cgi -> p; |
|
|
306 | |
|
|
307 | # Print list of bad addresses |
|
|
308 | print "The following student email addresses had fatal errors:\n", |
|
|
309 | $cgi -> ul( li( {-type=>'disc'},\@BadAddress ) ),"\n\n", |
|
|
310 | "You may choose to cancel your message or send it to the Good Addresses on your email list.\n<p>", |
|
|
311 | "To avoid this message in the future, you should correct these bad email addresses (the ones listed above) in your email list \n", |
|
|
312 | "and/or delete the students from your email list. Please ask your course coordinator for help with this.\n"; |
|
|
313 | # "If you are sending to the entire class, you may avoid these messages in the future by changing\n", |
|
|
314 | # "the status of the offending student(s) to 'Dropped'\n."; |
|
|
315 | |
|
|
316 | # start form with hidden entries to pass info back to profSendMail.pl |
|
|
317 | print $cgi->startform( -action=>"${cgiURL}profSendMail.pl" ), "\n", |
|
|
318 | $cgi -> hidden(-name=>"user", -value=>$user), "\n", |
|
|
319 | $cgi -> hidden(-name=>"key", -value=>$session_key), "\n", |
|
|
320 | $cgi -> hidden(-name=>"course", -value=>$course), "\n", |
|
|
321 | $cgi -> hidden(-name=>"To"), "\n", |
|
|
322 | $cgi -> hidden(-name=>"classList"), "\n", |
|
|
323 | $cgi -> hidden(-name=>"studentID"), "\n", |
|
|
324 | $cgi -> hidden(-name=>"merge"), "\n", |
|
|
325 | $cgi -> hidden(-name=>"mergeFiles"), "\n", |
|
|
326 | $cgi -> hidden(-name=>"mergeFile"), "\n", |
|
|
327 | $cgi -> hidden(-name=>"body"), "\n", |
|
|
328 | $cgi -> hidden(-name=>"from"), "\n", |
|
|
329 | $cgi -> hidden(-name=>"replyTo"), "\n", |
|
|
330 | $cgi -> hidden(-name=>"cc"), "\n", |
|
|
331 | $cgi -> hidden(-name=>"subject"), "\n", |
|
|
332 | $cgi -> hidden(-name=>"columns"), "\n", |
|
|
333 | $cgi -> hidden(-name=>"dummyName"), "\n", |
|
|
334 | $cgi -> hidden(-name=>"format"), "\n", |
|
|
335 | $cgi -> hidden(-name=>"openfilename"), "\n", |
|
|
336 | $cgi -> hidden(-name=>"rows"), "\n", |
|
|
337 | $cgi -> hidden(-name=>"savefilename"), "\n", |
|
|
338 | $cgi -> hidden(-name=>"no_record"), "\n"; |
|
|
339 | |
|
|
340 | |
|
|
341 | # create both necessary action buttons |
|
|
342 | print $cgi->submit(-name=>'action', -value=>'Send to Good Addresses'), "\n", |
|
|
343 | $cgi->submit(-name=>'action', -value=>'Cancel'),"\n", |
|
|
344 | $cgi->end_form, |
|
|
345 | &htmlBOTTOM("profSendMail", \%inputs, 'profSendMailHelp.html'); |
|
|
346 | |
|
|
347 | # End of HTML, and this part of the program |
|
|
348 | exit(0); |
|
|
349 | } |
|
|
350 | } |
|
|
351 | |
|
|
352 | |
|
|
353 | #if we want to send the e-mail anyway, or if there were no errors found |
|
|
354 | my @studentID = (); |
|
|
355 | |
|
|
356 | if( $cgi->param('To') eq 'classList' && defined( $cgi->param('classList') ) && $cgi->param('classList') ne 'None' ) { |
|
|
357 | my $classlist = $cgi->param('classList'); |
|
|
358 | my $classListFile = "$templateDirectory$classlist"; |
|
|
359 | my @classList = (); |
|
|
360 | checkClasslistFile($Global::noOfFieldsInClasslist,$classListFile); |
|
|
361 | |
|
|
362 | open(FILE, "$classListFile") || die "can't open $classListFile"; |
|
|
363 | @classList=<FILE>; |
|
|
364 | close(FILE); |
|
|
365 | |
|
|
366 | foreach (@classList) { ## read through classlist and send e-mail |
|
|
367 | ## message to all active students |
|
|
368 | next unless($_ =~ /\S/); ## skip blank lines |
|
|
369 | chomp; |
|
|
370 | |
|
|
371 | my @classListRecord = &getRecord($_); |
|
|
372 | my ($studentID, $lastName, $firstName, $status, $comment, $section, $recitation, $email_address, $login_name) |
|
|
373 | = @classListRecord; |
|
|
374 | unless( &dropStatus($status) || $login_name =~ /^$Global::practiceUser/ ) { |
|
|
375 | push (@studentID, $studentID); |
|
|
376 | |
|
|
377 | $fn{$studentID} = $firstName; |
|
|
378 | $ln{$studentID} = $lastName; |
|
|
379 | $section{$studentID} = $section; |
|
|
380 | $recitation{$studentID} = $recitation; |
|
|
381 | $status{$studentID} = $status; |
|
|
382 | $email{$studentID} = $email_address; |
|
|
383 | $login{$studentID} = $login_name; |
|
|
384 | } |
|
|
385 | } # end foreach |
|
|
386 | } |
|
|
387 | elsif ($cgi->param('To') eq 'studentID' && defined($cgi->param('studentID'))) { |
|
|
388 | @studentID = $cgi->param('studentID'); |
|
|
389 | my ($studentID, $login_name); |
|
|
390 | |
|
|
391 | foreach $studentID (@studentID) { |
|
|
392 | $login_name = $studentID_LoginName_Hash{$studentID}; |
|
|
393 | &attachCLRecord($login_name); |
|
|
394 | $fn{$studentID} = CL_getStudentFirstName($login_name); |
|
|
395 | $ln{$studentID} = CL_getStudentLastName($login_name); |
|
|
396 | $section{$studentID} = CL_getClassSection($login_name); |
|
|
397 | $recitation{$studentID} = CL_getClassRecitation($login_name); |
|
|
398 | $status{$studentID} = CL_getStudentStatus($login_name); |
|
|
399 | $email{$studentID} = CL_getStudentEmailAddress($login_name); |
|
|
400 | $login{$studentID} = $login_name; |
|
|
401 | } |
|
|
402 | |
|
|
403 | } |
|
|
404 | elsif ($cgi->param('To') eq 'all_students') { |
|
|
405 | @studentID = (); |
|
|
406 | my ($studentID, $login_name, $status); |
|
|
407 | |
|
|
408 | foreach $login_name (@availableStudents) { |
|
|
409 | &attachCLRecord($login_name); |
|
|
410 | $status = CL_getStudentStatus($login_name); |
|
|
411 | next if( &dropStatus($status) || $login_name =~ /^$Global::practiceUser/ ); |
|
|
412 | |
|
|
413 | $studentID = CL_getStudentID($login_name); |
|
|
414 | push(@studentID,$studentID); |
|
|
415 | |
|
|
416 | $fn{$studentID} = CL_getStudentFirstName($login_name); |
|
|
417 | $ln{$studentID} = CL_getStudentLastName($login_name); |
|
|
418 | $section{$studentID} = CL_getClassSection($login_name); |
|
|
419 | $recitation{$studentID} = CL_getClassRecitation($login_name); |
|
|
420 | $status{$studentID} = CL_getStudentStatus($login_name); |
|
|
421 | $email{$studentID} = CL_getStudentEmailAddress($login_name); |
|
|
422 | $login{$studentID} = $login_name; |
|
|
423 | } |
|
|
424 | } # end elsif |
|
|
425 | else { |
|
|
426 | &user_error('You didn\'t select any recipients. Make sure you select either all student in the course, individual students or a whole classlist.'); |
|
|
427 | } |
|
|
428 | |
|
|
429 | my $mergeFile = ''; |
|
|
430 | |
|
|
431 | #the radio button named 'merge' determines whether to take the selected mergefile |
|
|
432 | #or one that was typed in. A error message is given if select one and use the other |
|
|
433 | $mergeFile = $scoringDirectory . $cgi->param('mergeFiles') |
|
|
434 | if ($cgi->param('merge') eq 'mergeFiles' && defined($cgi->param('mergeFiles')) && $cgi->param('mergeFiles') ne 'None'); |
|
|
435 | |
|
|
436 | $mergeFile = $templateDirectory . $cgi->param('mergeFile') |
|
|
437 | if ($cgi->param('merge') eq 'mergeFile' && defined($cgi->param('mergeFile')) && $cgi->param('mergeFile') !~ m|/$|); #does not end in a / |
|
|
438 | |
|
|
439 | if( $mergeFile =~ /^[~.]/ || $mergeFile =~ /\.\./) { |
|
|
440 | &user_error( "For security reasons, you cannot specify a merge file from a directory higher than the email directory. Please specify a different file or move the needed file to the email directory" ); |
|
|
441 | } |
|
|
442 | if( $cgi->param('body') =~ /(\$COL\[.*?\])/ && !(-e $mergeFile) ) { |
|
|
443 | &user_error( "In order to use the \$COL[] you must specify a merge file. The file you specified does not exist. Also, make sure you selected the right checkbox." ); |
|
|
444 | } |
|
|
445 | |
|
|
446 | my %mergeAArray = (); |
|
|
447 | %mergeAArray = &delim2aa($mergeFile) unless $mergeFile eq ''; |
|
|
448 | |
|
|
449 | foreach my $studentID (@studentID) { |
|
|
450 | unless( ( defined $mergeAArray{$studentID} ) or ( $mergeFile eq '' ) ) { |
|
|
451 | next if $cgi->param('no_record'); |
|
|
452 | } |
|
|
453 | |
|
|
454 | @COL = (); |
|
|
455 | $SID = $studentID; |
|
|
456 | $LN = defined $ln{$studentID} ? $ln{$studentID} :''; |
|
|
457 | $FN = defined $fn{$studentID} ? $fn{$studentID} :''; |
|
|
458 | $SECTION = defined $section{$studentID} ? $section{$studentID} :''; |
|
|
459 | $RECITATION = defined $recitation{$studentID} ? $recitation{$studentID} :''; |
|
|
460 | $EMAIL = defined $email{$studentID} ? $email{$studentID} :''; |
|
|
461 | $STATUS = defined $status{$studentID} ? $status{$studentID} :''; |
|
|
462 | $LOGIN = $login{$studentID}; |
|
|
463 | |
|
|
464 | my( $dbString, @dbArray ); |
|
|
465 | if( defined $mergeAArray{$SID} ) { |
|
|
466 | $dbString = $mergeAArray{$SID}; ## get sid record from merge file |
|
|
467 | @dbArray = &getRecord($dbString); |
|
|
468 | unshift(@dbArray,$SID); |
|
|
469 | unshift(@dbArray,""); ## note COL[1] is the first column |
|
|
470 | @COL = @dbArray; ## put merge fields in COL array |
|
|
471 | $endCol = @COL; ## \endCol-1 gives last field, etc |
|
|
472 | } |
|
|
473 | $endCol = 0 unless defined $endCol; |
|
|
474 | |
| 318 | &user_error('You didn\'t enter any message.') if ($cgi->param('body') eq ''); |
475 | &user_error( 'You didn\'t enter any message.' ) if ($cgi->param('body') eq ''); |
| 319 | |
476 | |
| 320 | my $smtp = Net::SMTP->new($Global::smtpServer, Timeout=>10) || &internal_error("Couldn't contact SMTP server."); |
477 | my $smtp = Net::SMTP -> new( $Global::smtpServer, Timeout=>10 ) || &internal_error( "Couldn't contact SMTP server." ); |
| 321 | $smtp->mail($Global::webmaster); |
478 | $smtp -> mail( $Global::webmaster ); |
| 322 | # $smtp->mail($Global::feedbackAddress); |
479 | # $smtp->mail($Global::feedbackAddress); |
| 323 | |
480 | |
| 324 | if ( $smtp->recipient($EMAIL)) { # this one's okay, keep going |
481 | if( ( defined($cc) && $cc && $smtp->recipient($EMAIL,$cc) ) || ( $smtp -> recipient($EMAIL) ) ) { # this one's okay, keep going |
| 325 | $smtp->data(output() ) || |
482 | $smtp -> data( output() ) || |
| 326 | &internal_error("Unknown problem sending message data to SMTP server."); |
483 | &internal_error( "Unknown problem sending message data to SMTP server." ); |
|
|
484 | } |
| 327 | } else { # we have a problem a problem with this address |
485 | else { # we have a problem a problem with this address |
| 328 | $smtp->reset; |
486 | $smtp -> reset; |
| 329 | &internal_error("SMTP server doesn't like this address: <$EMAIL>."); |
487 | # &internal_error( "SMTP server doesn't like this address: <$EMAIL> or <$cc>." ); |
|
|
488 | #I'm not sure why the above line is commented out -- it might be a mistake (but it might not...) |
| 330 | } |
489 | } |
| 331 | $smtp->quit; |
490 | $smtp -> quit; |
| 332 | } |
491 | } # end foreach |
|
|
492 | |
| 333 | &success; |
493 | &success; |
| 334 | } |
494 | } |
| 335 | } |
495 | } |
| 336 | |
496 | |
| 337 | |
497 | |
| 338 | |
498 | |
| 339 | #Begin Page |
499 | #Begin Page |
| 340 | print &htmlTOP("Send Mail for " . $course), |
500 | print &htmlTOP("Send Mail for " . $course), |
| … | |
… | |
| 475 | |
635 | |
| 476 | print $cgi->hr, $cgi->p, $cgi->b('Enter Message: '), "\n", $cgi->br; |
636 | print $cgi->hr, $cgi->p, $cgi->b('Enter Message: '), "\n", $cgi->br; |
| 477 | #get message from given messageFileName |
637 | #get message from given messageFileName |
| 478 | my ($text, @text); |
638 | my ($text, @text); |
| 479 | my $header = ''; |
639 | my $header = ''; |
| 480 | my ($subject, $from, $replyTo); |
640 | my ($subject, $from, $replyTo, $cc); |
| 481 | if (-e "$emailDirectory$messageFileName") { |
641 | if (-e "$emailDirectory$messageFileName") { |
| 482 | open FILE, "$emailDirectory$messageFileName"; |
642 | open FILE, "$emailDirectory$messageFileName"; |
| 483 | while ($header !~ s/Message:\s*$//m) { $header .= <FILE>; } |
643 | while ($header !~ s/Message:\s*$//m) { $header .= <FILE>; } |
| 484 | $text = join "", <FILE>; |
644 | $text = join "", <FILE>; |
| 485 | |
645 | |
| 486 | $header =~ /^From:\s*(.*)$/m; |
646 | $header =~ /^From:\s*(.*)$/m; |
| 487 | $from = $1 or $from = $feedbackAddress; #given email address or default feedback address |
647 | $from = $1 or $from = $feedbackAddress; #given email address or default feedback address |
| 488 | $header =~ /^Reply-To:\s*(.*)$/m; |
648 | $header =~ /^Reply-To:\s*(.*)$/m; |
| 489 | $replyTo = $1 or $replyTo = $feedbackAddress; |
649 | $replyTo = $1 or $replyTo = $feedbackAddress; |
|
|
650 | $header =~ /^Cc:\s*(.*)$/m; |
|
|
651 | $cc = $1; |
| 490 | $header =~ /^Subject:\s*(.*)$/m; |
652 | $header =~ /^Subject:\s*(.*)$/m; |
| 491 | $subject = $1; |
653 | $subject = $1; |
| 492 | |
654 | |
| 493 | |
655 | |
| 494 | } else { |
656 | } else { |
| 495 | # wwerror($0, "Message File $emailDirectory$messageFileName does not exist!"); |
657 | # wwerror($0, "Message File $emailDirectory$messageFileName does not exist!"); |
| 496 | } |
658 | } |
| 497 | |
659 | |
| 498 | # show professors's name and email address |
660 | # show professors's name and email address |
| 499 | print "\n", $cgi->p, $cgi->b('From: '), $cgi->textfield(-name=>"from", -size=>40, -value=>$from, -override=>1), |
661 | print "\n", $cgi->p, $cgi->b('From: '), $cgi->textfield(-name=>"from", -size=>40, -value=>$from, -override=>1), |
| 500 | "\n", $cgi->p, $cgi->b('Reply-To: '), $cgi->textfield(-name=>"replyTo", -size=>40, -value=>$replyTo, -override=>1); |
662 | "\n", $cgi->p, $cgi->b('Reply-To: '), $cgi->textfield(-name=>"replyTo", -size=>40, -value=>$replyTo, -override=>1), |
|
|
663 | "\n", $cgi->p, $cgi->b('Cc: '), $cgi->textfield(-name=>"cc", -size=>40, -value=>$cc, -override=>1); |
| 501 | |
664 | |
| 502 | #create a textbox with the subject and a textarea with the message |
665 | #create a textbox with the subject and a textarea with the message |
| 503 | |
666 | |
| 504 | print "\n", $cgi->p, $cgi->b('Subject: '), $cgi->textfield(-name=>'subject', -default=>$subject, -size=>40, -override=>1), |
667 | print "\n", $cgi->p, $cgi->b('Subject: '), $cgi->textfield(-name=>'subject', -default=>$subject, -size=>40, -override=>1), |
| 505 | $cgi->p, |
668 | $cgi->p, |
| … | |
… | |
| 685 | |
848 | |
| 686 | |
849 | |
| 687 | $msg = |
850 | $msg = |
| 688 | # message header |
851 | # message header |
| 689 | "From: " . $cgi->param('from') . "\n" . |
852 | "From: " . $cgi->param('from') . "\n" . |
|
|
853 | "To: " . $FN . ' ' . $LN . '<' . $EMAIL . '>' . "\n" . |
| 690 | "Reply-To: " . $cgi->param('replyTo') . "\n" . |
854 | "Reply-To: " . $cgi->param('replyTo') . "\n" . |
|
|
855 | "Cc: " . $cgi->param('cc') . "\n" . |
| 691 | "Subject: ". $cgi->param('subject') . "\n" . |
856 | "Subject: " . $cgi->param('subject') . "\n" . |
| 692 | "\n" . $tmp . "\n"; |
857 | "\n" . $tmp . "\n"; |
| 693 | |
858 | |
| 694 | $msg =~ s/\r//g; |
859 | $msg =~ s/\r//g; |
| 695 | return $msg; |
860 | return $msg; |
| 696 | } |
861 | } |
| 697 | |
862 | |
| 698 | sub success { |
863 | sub success { |
| 699 | print $cgi->header, |
864 | # Begin Page with a header |
| 700 | $cgi->start_html( '-title'=>'Email Sent'), |
865 | print htmlTOP("Send Mail for " . $course), |
|
|
866 | $cgi->a( { -href=>"${cgiURL}profLogin.pl?user=$user&key=$session_key&course=$course" }, |
|
|
867 | $cgi->img({ -name=>'upImg', -src=>"${Global::upImgUrl}", -align=>'right', -border=>'1', -alt=>'[Up]'})), |
|
|
868 | $cgi->p; |
|
|
869 | |
|
|
870 | # Page title |
|
|
871 | print "\n",$cgi->hr, $cgi->br,"\n\n", |
|
|
872 | $cgi->h3({ -align=>'left' }, "Email Sent for $course"), "\n", |
|
|
873 | $cgi->p; |
|
|
874 | |
|
|
875 | # Print list of bad addresses |
| 701 | $cgi->h1('Your message has been sent.'), |
876 | print $cgi->h1('Your message has been sent.'),"\n"; |
| 702 | $cgi->end_html; |
877 | |
|
|
878 | |
|
|
879 | # start form with hidden entries to pass info back to profSendMail.pl |
|
|
880 | print $cgi->startform(-action=>"${cgiURL}profSendMail.pl"), "\n", |
|
|
881 | $cgi->hidden(-name=>"user", -value=>$user), "\n", |
|
|
882 | $cgi->hidden(-name=>"key", -value=>$session_key), "\n", |
|
|
883 | $cgi->hidden(-name=>"course", -value=>$course), "\n"; |
|
|
884 | |
|
|
885 | # create the action button |
|
|
886 | print $cgi->submit(-name=>'.submit', -value=>'Return to Send Email Page'),"\n", |
|
|
887 | $cgi->end_form, |
|
|
888 | htmlBOTTOM("profSendMail", \%inputs, 'profSendMailHelp.html'); |
|
|
889 | |
|
|
890 | # End of HTML, and this part of the program |
| 703 | exit(0); |
891 | exit(0); |
| 704 | } |
892 | } |