Parent Directory
|
Revision Log
Revision 404 - (view) (download) (as text)
| 1 : | sh002i | 404 | package IOGlue; |
| 2 : | use strict; | ||
| 3 : | use warnings; | ||
| 4 : | |||
| 5 : | our @ISA = qw(Exporter); | ||
| 6 : | our @EXPORT = qw( | ||
| 7 : | includePGtext | ||
| 8 : | send_mail_to | ||
| 9 : | read_whole_problem_file | ||
| 10 : | read_whole_file | ||
| 11 : | convertPath | ||
| 12 : | getDirDelim | ||
| 13 : | getCourseTempDirectory | ||
| 14 : | surePathToTmpFile | ||
| 15 : | fileFromPath | ||
| 16 : | directoryFromPath | ||
| 17 : | createFile | ||
| 18 : | createDirectory | ||
| 19 : | REMOTE_HOST | ||
| 20 : | REMOTE_ADDR | ||
| 21 : | ); | ||
| 22 : | |||
| 23 : | |||
| 24 : | =head2 Private functions (not methods) used by PGtranslator for file IO. | ||
| 25 : | =cut | ||
| 26 : | |||
| 27 : | our $REMOTE_HOST = (defined( $ENV{'REMOTE_HOST'} ) ) ? $ENV{'REMOTE_HOST'}: 'unknown host'; | ||
| 28 : | our $REMOTE_ADDR = (defined( $ENV{'REMOTE_ADDR'}) ) ? $ENV{'REMOTE_ADDR'}: 'unknown address'; | ||
| 29 : | |||
| 30 : | |||
| 31 : | =head2 includePGtext | ||
| 32 : | |||
| 33 : | includePGtext($string_ref, $envir_ref) | ||
| 34 : | |||
| 35 : | Calls C<createPGtext> recursively with the $safeCompartment variable set to 0 | ||
| 36 : | so that the rendering continues in the current safe compartment. The output | ||
| 37 : | is the same as the output from createPGtext. This is used in processing | ||
| 38 : | some of the sample CAPA files. | ||
| 39 : | |||
| 40 : | =cut | ||
| 41 : | |||
| 42 : | |||
| 43 : | sub includePGtext { | ||
| 44 : | my $evalString = shift; | ||
| 45 : | if (ref($evalString) eq 'SCALAR') { | ||
| 46 : | $evalString = $$evalString; | ||
| 47 : | } | ||
| 48 : | $evalString =~ s/\nBEGIN_TEXT/TEXT\(EV3\(<<'END_TEXT'\)\);/g; | ||
| 49 : | $evalString =~ s/\\/\\\\/g; # \ can't be used for escapes because of TeX conflict | ||
| 50 : | $evalString =~ s/~~/\\/g; # use ~~ as escape instead, use # for comments | ||
| 51 : | no strict; | ||
| 52 : | eval("package main; $evalString") ; | ||
| 53 : | my $errors = $@; | ||
| 54 : | die eval(q! "ERROR in included file:\n$main::envir{probFileName}\n $errors\n"!) if $errors; | ||
| 55 : | use strict; | ||
| 56 : | ''; | ||
| 57 : | } | ||
| 58 : | |||
| 59 : | |||
| 60 : | |||
| 61 : | =head2 send_mail_to | ||
| 62 : | |||
| 63 : | send_mail_to($user_address,'subject'=>$subject,'body'=>$body) | ||
| 64 : | |||
| 65 : | Returns: 1 if the address is ok, otherwise a fatal error is signaled using wwerror. | ||
| 66 : | |||
| 67 : | Sends $body to the address specified by $user_address provided that | ||
| 68 : | the address appears in C<@{$Global::PG_environment{'ALLOW_MAIL_TO'}}>. | ||
| 69 : | |||
| 70 : | This subroutine is likely to be fragile and to require tweaking when installed | ||
| 71 : | in a new environment. It uses the unix application C<sendmail>. | ||
| 72 : | |||
| 73 : | =cut | ||
| 74 : | |||
| 75 : | |||
| 76 : | sub send_mail_to { | ||
| 77 : | my $user_address = shift; # user must be an instructor | ||
| 78 : | my %options = @_; | ||
| 79 : | my $subject = ''; | ||
| 80 : | $subject = $options{'subject'} if defined($options{'subject'}); | ||
| 81 : | my $msg_body = ''; | ||
| 82 : | $msg_body =$options{'body'} if defined($options{'body'}); | ||
| 83 : | my @mail_to_allowed_list = (); | ||
| 84 : | @mail_to_allowed_list = @{ $options{'ALLOW_MAIL_TO'} } if defined($options{'ALLOW_MAIL_TO'}); | ||
| 85 : | my $out; | ||
| 86 : | |||
| 87 : | # check whether user is an instructor | ||
| 88 : | my $mailing_allowed_flag =0; | ||
| 89 : | |||
| 90 : | |||
| 91 : | while (@mail_to_allowed_list) { | ||
| 92 : | if ($user_address eq shift @mail_to_allowed_list ) { | ||
| 93 : | $mailing_allowed_flag =1; | ||
| 94 : | last; | ||
| 95 : | } | ||
| 96 : | } | ||
| 97 : | if ($mailing_allowed_flag) { | ||
| 98 : | ## mail header text: | ||
| 99 : | my $email_msg ="To: $user_address\n" . | ||
| 100 : | "X-Remote-Host: $REMOTE_HOST($REMOTE_ADDR)\n" . | ||
| 101 : | "Subject: $subject\n\n" . $msg_body; | ||
| 102 : | my $smtp = Net::SMTP->new($Global::smtpServer, Timeout=>10) || | ||
| 103 : | warn "Couldn't contact SMTP server."; | ||
| 104 : | $smtp->mail($Global::webmaster); | ||
| 105 : | |||
| 106 : | if ( $smtp->recipient($user_address)) { # this one's okay, keep going | ||
| 107 : | $smtp->data( $email_msg) || | ||
| 108 : | warn("Unknown problem sending message data to SMTP server."); | ||
| 109 : | } else { # we have a problem a problem with this address | ||
| 110 : | $smtp->reset; | ||
| 111 : | warn "SMTP server doesn't like this address: <$user_address>."; | ||
| 112 : | } | ||
| 113 : | $smtp->quit; | ||
| 114 : | |||
| 115 : | } else { | ||
| 116 : | |||
| 117 : | Global::wwerror("$0","There has been an error in creating this problem.\n" . | ||
| 118 : | "Please notify your instructor.\n\n" . | ||
| 119 : | "Mail is not permitted to address $user_address.\n" . | ||
| 120 : | "Permitted addresses are specified in the courseWeBWorK.ph file.", | ||
| 121 : | "","",""); | ||
| 122 : | $out = 0; | ||
| 123 : | } | ||
| 124 : | |||
| 125 : | $out; | ||
| 126 : | |||
| 127 : | } | ||
| 128 : | # only files are loaded first from the macroDirectory and then from the courseScriptsDirectory | ||
| 129 : | # files cannot be loaded from other directories. | ||
| 130 : | |||
| 131 : | |||
| 132 : | |||
| 133 : | |||
| 134 : | # | ||
| 135 : | # # these have been copied over from FILE.pl. I don't know if they need to be duplicated or not. | ||
| 136 : | # ## these call backs come from PGchoice -- mostly from within the alias command. | ||
| 137 : | # | ||
| 138 : | |||
| 139 : | =head2 read_whole_problem_file | ||
| 140 : | |||
| 141 : | read_whole_problem_file($filePath); | ||
| 142 : | |||
| 143 : | Returns: A reference to a string containing | ||
| 144 : | the contents of the file. | ||
| 145 : | |||
| 146 : | Don't use for huge files. The file name will have .pg appended to it if it doesn't | ||
| 147 : | already end in .pg. Files may become double spaced.? Check the join below. This is | ||
| 148 : | used in importing additional .pg files as is done in the | ||
| 149 : | sample problems translated from CAPA. | ||
| 150 : | |||
| 151 : | =cut | ||
| 152 : | |||
| 153 : | |||
| 154 : | sub read_whole_problem_file { | ||
| 155 : | my $filePath = shift; | ||
| 156 : | $filePath =~s/^\s*//; # get rid of initial spaces | ||
| 157 : | $filePath =~s/\s*$//; # get rid of final spaces | ||
| 158 : | $filePath = "$filePath.pg" unless $filePath =~ /\.pg$/; | ||
| 159 : | read_whole_file($filePath); | ||
| 160 : | } | ||
| 161 : | |||
| 162 : | sub read_whole_file { | ||
| 163 : | my $filePath = shift; | ||
| 164 : | local (*INPUT); | ||
| 165 : | open(INPUT, "<$filePath")|| die "$0: readWholeProblemFile subroutine: <BR>Can't read file $filePath"; | ||
| 166 : | local($/)=undef; | ||
| 167 : | my $string = <INPUT>; # can't append spaces because this causes trouble with <<'EOF' \nEOF construction | ||
| 168 : | close(INPUT); | ||
| 169 : | \$string; | ||
| 170 : | } | ||
| 171 : | |||
| 172 : | |||
| 173 : | =head2 convertPath | ||
| 174 : | |||
| 175 : | $path = convertPath($path); | ||
| 176 : | |||
| 177 : | Normalizes the delimiters in the path using delimiter from C<&getDirDelim()> | ||
| 178 : | which is defined in C<Global.pm>. | ||
| 179 : | |||
| 180 : | =cut | ||
| 181 : | |||
| 182 : | ## converts full path names to to use the $dirDelim instead of / | ||
| 183 : | |||
| 184 : | sub convertPath { | ||
| 185 : | return @_; | ||
| 186 : | } | ||
| 187 : | |||
| 188 : | # hacks to make this program work independent of Global.pm | ||
| 189 : | sub getDirDelim { | ||
| 190 : | return ("/"); | ||
| 191 : | } | ||
| 192 : | sub getCourseTempDirectory { | ||
| 193 : | return ($Global::courseTempDirectory); | ||
| 194 : | } | ||
| 195 : | |||
| 196 : | =head2 surePathToTmpFile | ||
| 197 : | |||
| 198 : | surePathToTmpFile($path) | ||
| 199 : | Returns: $path | ||
| 200 : | |||
| 201 : | Defined in FILE.pl | ||
| 202 : | |||
| 203 : | Creates all of the subdirectories between the directory specified | ||
| 204 : | by C<&getCourseTempDirectory> and the address of the path. | ||
| 205 : | |||
| 206 : | Uses | ||
| 207 : | |||
| 208 : | &createDirectory($path,$Global::tmp_directory_permission, $Global::numericalGroupID) | ||
| 209 : | |||
| 210 : | The path may begin with the correct path to the temporary | ||
| 211 : | directory. Any other prefix causes a path relative to the temporary | ||
| 212 : | directory to be created. | ||
| 213 : | |||
| 214 : | The quality of the error checking could be improved. :-) | ||
| 215 : | |||
| 216 : | =cut | ||
| 217 : | |||
| 218 : | # A very useful macro for making sure that all of the directories to a file have been constructed. | ||
| 219 : | |||
| 220 : | sub surePathToTmpFile { # constructs intermediate directories if needed beginning at ${Global::htmlDirectory}tmp/ | ||
| 221 : | # the input path must be either the full path, or the path relative to this tmp sub directory | ||
| 222 : | my $path = shift; | ||
| 223 : | my $delim = &getDirDelim(); | ||
| 224 : | my $tmpDirectory = getCourseTempDirectory(); | ||
| 225 : | # if the path starts with $tmpDirectory (which is permitted but optional) remove this initial segment | ||
| 226 : | $path =~ s|^$tmpDirectory|| if $path =~ m|^$tmpDirectory|; | ||
| 227 : | $path = convertPath($path); | ||
| 228 : | # find the nodes on the given path | ||
| 229 : | my @nodes = split("$delim",$path); | ||
| 230 : | # create new path | ||
| 231 : | $path = convertPath("$tmpDirectory"); | ||
| 232 : | |||
| 233 : | while (@nodes>1 ) { | ||
| 234 : | $path = convertPath($path . shift (@nodes) ."/"); | ||
| 235 : | unless (-e $path) { | ||
| 236 : | # system("mkdir $path"); | ||
| 237 : | createDirectory($path,$Global::tmp_directory_permission, $Global::numericalGroupID) || | ||
| 238 : | Global::wwerror($0, "Failed to create directory $path","","",""); | ||
| 239 : | |||
| 240 : | } | ||
| 241 : | |||
| 242 : | } | ||
| 243 : | $path = convertPath($path . shift(@nodes)); | ||
| 244 : | |||
| 245 : | # system(qq!echo "" > $path! ); | ||
| 246 : | |||
| 247 : | $path; | ||
| 248 : | |||
| 249 : | } | ||
| 250 : | |||
| 251 : | |||
| 252 : | =head2 fileFromPath | ||
| 253 : | |||
| 254 : | $fileName = fileFromPath($path) | ||
| 255 : | |||
| 256 : | Defined in C<FILE.pl>. | ||
| 257 : | |||
| 258 : | Uses C<&getDirDelim()> to determine the path delimiter. Returns the last segment | ||
| 259 : | of the path (after the last delimiter.) | ||
| 260 : | |||
| 261 : | =cut | ||
| 262 : | |||
| 263 : | sub fileFromPath { | ||
| 264 : | my $path = shift; | ||
| 265 : | my $delim =&getDirDelim(); | ||
| 266 : | $path = convertPath($path); | ||
| 267 : | $path =~ m|([^$delim]+)$|; | ||
| 268 : | $1; | ||
| 269 : | |||
| 270 : | } | ||
| 271 : | |||
| 272 : | =head2 directoryFromPath | ||
| 273 : | |||
| 274 : | |||
| 275 : | $directoryPath = directoryFromPath($path) | ||
| 276 : | |||
| 277 : | Defined in C<FILE.pl>. | ||
| 278 : | |||
| 279 : | Uses C<&getDirDelim()> to determine the path delimiter. Returns the initial segments | ||
| 280 : | of the of the path (up to the last delimiter.) | ||
| 281 : | |||
| 282 : | =cut | ||
| 283 : | |||
| 284 : | sub directoryFromPath { | ||
| 285 : | my $path = shift; | ||
| 286 : | my $delim =&getDirDelim(); | ||
| 287 : | $path = convertPath($path); | ||
| 288 : | $path =~ s|[^$delim]*$||; | ||
| 289 : | $path; | ||
| 290 : | } | ||
| 291 : | |||
| 292 : | =head2 createFile | ||
| 293 : | |||
| 294 : | createFile($filePath); | ||
| 295 : | |||
| 296 : | Calls C<FILE.pl> version of createFile with | ||
| 297 : | C<createFile($filePath,0660(permission),$Global::numericalGroupID)> | ||
| 298 : | |||
| 299 : | =cut | ||
| 300 : | |||
| 301 : | sub createFile { | ||
| 302 : | my ($fileName, $permission, $numgid) = @_; | ||
| 303 : | open(TEMPCREATEFILE, ">$fileName") || | ||
| 304 : | Global::wwerror("File.pl: createFile error", " Can't open $fileName"); | ||
| 305 : | my @stat = stat TEMPCREATEFILE; | ||
| 306 : | close(TEMPCREATEFILE); | ||
| 307 : | |||
| 308 : | ## if the owner of the file is running this script (e.g. when the file is first created) | ||
| 309 : | ## set the permissions and group correctly | ||
| 310 : | if ($< == $stat[4]) { | ||
| 311 : | my $tmp = chmod($permission,$fileName) or | ||
| 312 : | warn("File.pl: createFile error", " Can't do chmod($permission, $fileName)"); | ||
| 313 : | chown(-1,$numgid,$fileName) or | ||
| 314 : | warn("File.pl: createFile error", " Can't do chown($numgid, $fileName)"); | ||
| 315 : | } | ||
| 316 : | } | ||
| 317 : | |||
| 318 : | sub createDirectory | ||
| 319 : | { | ||
| 320 : | my ($dirName, $permission, $numgid) = @_; | ||
| 321 : | mkdir($dirName, $permission) or | ||
| 322 : | warn("$0: createDirectory error", " Can't do mkdir($dirName, $permission)"); | ||
| 323 : | chmod($permission, $dirName) or | ||
| 324 : | warn("$0: createDirectory error", " Can't do chmod($permission, $dirName)"); | ||
| 325 : | unless ($numgid == -1) {chown(-1,$numgid,$dirName) or | ||
| 326 : | warn("$0: createDirectory error", " Can't do chown(-1,$numgid,$dirName)");} | ||
| 327 : | } | ||
| 328 : | |||
| 329 : | 1; |
| aubreyja at gmail dot com | ViewVC Help |
| Powered by ViewVC 1.0.9 |