From cc6ebd36e0068bbefa0102fe0e51133dcf1b8b42 Mon Sep 17 00:00:00 2001 From: Vamsi Krishna Davuluri Date: Mon, 10 Aug 2009 09:15:19 +0000 Subject: Added aa's spinbutton suggestion. added Moodle Print Module as sub directory. --- diff --git a/.gitignore b/.gitignore index 3c16e81..3c16e81 100644..100755 --- a/.gitignore +++ b/.gitignore diff --git a/.goutputstream-JNP5VU b/.goutputstream-JNP5VU index e69de29..e69de29 100644..100755 --- a/.goutputstream-JNP5VU +++ b/.goutputstream-JNP5VU diff --git a/.goutputstream-ST50VU b/.goutputstream-ST50VU index e69de29..e69de29 100644..100755 --- a/.goutputstream-ST50VU +++ b/.goutputstream-ST50VU diff --git a/AUTHORS b/AUTHORS index fe61bd3..fe61bd3 100644..100755 --- a/AUTHORS +++ b/AUTHORS diff --git a/COPYING b/COPYING index d511905..d511905 100644..100755 --- a/COPYING +++ b/COPYING diff --git a/Moodle/mod/print/BasicIPP.php b/Moodle/mod/print/BasicIPP.php new file mode 100755 index 0000000..6537fd2 --- /dev/null +++ b/Moodle/mod/print/BasicIPP.php @@ -0,0 +1,1832 @@ +errno = $errno; + } + + public function getErrorFormatted() { + + $return = sprintf("[ipp]: %s -- "._(" file %s, line %s"), + $this->getMessage(), + $this->getFile(), + $this->getLine()); + + return $return; + } + + public function getErrno() { + + return $this->errno ; + } + +} + // }}} + + + +class BasicIPP { + + // {{{ variables declaration + // setup variables + public $paths = array("root" => "/", + "admin" => "/admin/", + "printers" => "/printers/", + "jobs" => "/jobs/"); + public $http_timeout = 0; // timeout at http connection (seconds) 0 => default => 30. + public $http_data_timeout = 0; // data reading timeout (milliseconds) 0 => default => 30. + public $ssl = false; + public $debug_level = 3; // max 3: almost silent + public $alert_on_end_tag;// debugging purpose: echo "END tag OK" if (1 and reads while end tag) + public $with_exceptions = 0; // compatibility mode for old scripts + public $handle_http_exceptions = 1; + // readables variables + public $jobs = array(); + public $jobs_uri = array(); + public $status = array(); + public $response_completed = array(); + public $last_job = ""; + public $attributes; // object you can read: attributes after validateJob() + public $printer_attributes; // object you can read: printer's attributes after getPrinterAttributes() + public $job_attributes; // object you can read: last job attributes + public $jobs_attributes; // object you can read: jobs attributes after getJobs() + public $available_printers = array(); + public $printers_uri = array(); + public $debug = array(); + public $response; + + // {{{ protected variables; + + protected $log_level = 2; // max 3: very verbose + protected $log_type = 3; // 3: file | 1: e-mail | 0: logger + protected $log_destination; // e-mail or file + protected $serveroutput; + protected $setup; + protected $stringjob; + protected $data; + protected $debug_count = 0; + protected $username; + protected $charset; + protected $password; + protected $requesring_user; + protected $client_hostname = "localhost"; + protected $stream; + protected $host = "localhost"; + protected $port = "631"; + protected $printer_uri; + protected $timeout = "20"; //20 secs + protected $errNo; + protected $errStr; + protected $datatype; + protected $datahead; + protected $datatail; + public $meta; + protected $operation_id; + protected $delay; + protected $error_generation; //devel feature + protected $debug_http = 0; + protected $no_disconnect; + protected $job_tags; + protected $operation_tags; + protected $index; + protected $collection ; //RFC3382 + protected $collection_index; //RFC3382 + protected $collection_key = array(); //RFC3382 + protected $collection_depth = -1; //RFC3382 + protected $end_collection = false; //RFC3382 + protected $collection_nbr = array(); //RFC3382 + protected $unix = false; // true -> use unix sockets instead of http + // }}} + // }}} + + // {{{ constructor + public function __construct() { + $tz = getenv("date.timezone"); + if (!$tz) + $tz = date_default_timezone_get(); + date_default_timezone_set($tz); + + $this->meta = new stdClass(); + $this->setup = new stdClass(); + $this->values = new stdClass(); + $this->serveroutput = new stdClass(); + $this->error_generation = new stdClass(); + $this->_parsing = new stdClass(); + + self::_initTags (); + } + // }}} + +/***************** +* +* PUBLIC FUNCTIONS +* +*******************/ + + +// SETUP + + // {{{ setPort($port='631') + public function setPort($port='631'){ + $this->port = $port; + self::_putDebug("Port is ".$this->port,2); + } + // }}} + + // {{{ setUnix($socket='/var/run/cups/cups.sock') + public function setUnix($socket='/var/run/cups/cups.sock') { + $this->host = $socket; + $this->unix = true; + self::_putDebug("Host is ".$this->host,2); + } + // }}} + + // {{{ setHost($host='localhost') + public function setHost($host='localhost'){ + $this->host = $host; + $this->unix = false; + self::_putDebug("Host is ".$this->host,2); + } + // }}} + + // {{{ setTimeout($timeout) + public function setTimeout($timeout){ + $this->timeout = $timeout; + } + // }}} + + // {{{ setPrinterURI ($uri) + public function setPrinterURI ($uri) { + + + $length = strlen ($uri); + $length = chr($length); + + while (strlen($length) < 2) + $length = chr(0x00) . $length; + + $this->meta->printer_uri = chr(0x45) // uri type | value-tag + . chr(0x00) . chr(0x0B) // name-length + . "printer-uri" // printer-uri | name + . $length + . $uri; + + $this->printer_uri = $uri; + + self::_putDebug(sprintf(_("Printer URI: %s"),$uri),2); + + $this->setup->uri = 1; + + } + // }}} + + // {{{ setData($data) + public function setData($data){ + // + $this->data = $data; + self::_putDebug("Data set",2); + } + // }}} + + // {{{ setRawText () + public function setRawText () { + $this->setup->datatype = 'TEXT'; + $this->meta->mime_media_type = ""; + $this->setup->mime_media_type = 1; + $this->datahead = chr(0x16); + + if (is_readable($this->data)){ + //It's a filename. Open and stream. + $data = fopen($this->data, "rb"); + while(!feof($data)) + $output = fread($data, 8192); + } else { + $output = $this->data; + } + + if (substr($output,-1,1) != chr(0x0c)) + if (!isset($this->setup->noFormFeed)) + $this->datatail = chr(0x0c); + + self::_putDebug(_("Forcing data to be interpreted as RAW TEXT"),2); + } + // }}} + + // {{{ unsetRawText () + public function unsetRawText () { + + $this->setup->datatype = 'BINARY'; + $this->datahead = ''; + $this->datatail = ''; + self::_putDebug(_("Unset forcing data to be interpreted as RAW TEXT"),2); + + } + // }}} + + // {{{ setBinary() + public function setBinary () { + self::unsetRawText(); + } + // }}} + + // {{{ setFormFeed () + public function setFormFeed () { + $this->datatail = "\r\n".chr(0x0c); + unset($this->setup->noFormFeed); + } + // }}} + + // {{{ unsetFormFeed () + public function unsetFormFeed () { + $this->datatail = ''; + $this->setup->noFormFeed = 1; + } + // }}} + + // {{{ setCharset ($charset) + public function setCharset ($charset='us-ascii') { + + $charset = strtolower($charset); + $this->charset = $charset; + + $this->meta->charset = chr(0x47) // charset type | value-tag + . chr(0x00) . chr(0x12) // name-length + . "attributes-charset" // attributes-charset | name + . self::_giveMeStringLength($charset) // value-length + . $charset; // value + + self::_putDebug(sprintf(_("Charset: %s"),$charset),2); + + $this->setup->charset = 1; + } + // }}} + + // {{{ setLanguage($language) + public function setLanguage($language='en_us') { + + $language = strtolower($language); + + $this->meta->language = chr(0x48) // natural-language type | value-tag + . chr(0x00) . chr(0x1B) // name-length + . "attributes-natural-language" //attributes-natural-language + . self::_giveMeStringLength($language) // value-length + . $language; // value + + self::_putDebug(sprintf(_("Language: %s"),$language),2); + + $this->setup->language = 1; + } + // }}} + + // {{{ setMimeMediaType ($mime_media_type='application/octet-stream') + public function setMimeMediaType ($mime_media_type='') { + + self::setBinary(); + + $length = strlen ($mime_media_type); + if ($length == 0) + { + $this->meta->mime_media_type = ""; + } + else + { + $length = chr($length); + + while (strlen($length) < 2) + $length = chr(0x00) . $length; + + + self::_putDebug( sprintf(_("mime type: %s"),$mime_media_type),2); + + $this->meta->mime_media_type = chr(0x49) // document-format tag + . self::_giveMeStringLength('document-format') + . 'document-format' // + . self::_giveMeStringLength($mime_media_type) + . $mime_media_type; // value + } + $this->setup->mime_media_type = 1; + } + // }}} + + // {{{ setDocumentFormat ($mime_media_type="application/octet-stream") // setMimeMediaType alias + public function setDocumentFormat ($mime_media_type="application/octet-stream") { + self::setMimeMediaType ($mime_media_type); + } + // }}} + + // {{{ setCopies ($nbrcopies=1) + public function setCopies ($nbrcopies=1) { + + $this->meta->copies = ""; + if ($nbrcopies == 1 || !$nbrcopies) + return true; + + $copies = self::_integerBuild($nbrcopies); + + $this->meta->copies = chr(0x21) // integer type | value-tag + . chr(0x00) .chr(0x06) // name-length + . "copies" // copies | name + . self::_giveMeStringLength($copies) // value-length + . $copies; + + self::_putDebug( sprintf(_("Copies: %s"),$nbrcopies),2); + + $this->setup->copies = 1; + + } + // }}} + + // {{{ setDocumentName ($document_name) + public function setDocumentName ($document_name="") { + + $this->meta->document_name = ""; + if (!$document_name) + return true; + + $document_name = substr($document_name,0,1023); + + $length = strlen ($document_name); + $length = chr($length); + + while (strlen($length) < 2) + $length = chr(0x00) . $length; + + + self::_putDebug( sprintf(_("document name: %s"),$document_name),2); + + $this->meta->document_name = chr(0x41) // textWithoutLanguage tag + . chr(0x00) . chr(0x0d) // name-length + . "document-name" // mimeMediaType + . self::_giveMeStringLength($document_name) + . $document_name; // value + + } + // }}} + + // {{{ setJobName ($jobname='(PHP)',$absolute=false) + public function setJobName ($jobname='',$absolute=false) { + + $this->meta->jobname = ''; + if ($jobname=='') + { + $this->meta->jobname = ''; + return true; + } + $postpend = date('-H:i:s-') . $this->_setJobId(); + + if ($absolute) + $postpend = ''; + + if (isset($this->values->jobname) && $jobname == '(PHP)') + $jobname = $this->values->jobname; + + $this->values->jobname = $jobname; + + $jobname .= $postpend; + + $this->meta->jobname = chr(0x42) // nameWithoutLanguage type || value-tag + . chr(0x00) . chr(0x08) // name-length + . "job-name" // job-name || name + . self::_giveMeStringLength($jobname) // value-length + . $jobname ; // value + + self::_putDebug( sprintf(_("Job name: %s"),$jobname),2); + $this->setup->jobname = 1; + } + // }}} + + // {{{ setUserName ($username='PHP-SERVER') + public function setUserName ($username='PHP-SERVER') { + + $this->requesting_user = $username; + $this->meta->username = ''; + if (!$username) + return true; + + if ($username == 'PHP-SERVER' && isset($this->meta->username)) + return TRUE; + + $value_length = 0x00; + for ($i = 0 ; $i < strlen($username) ; $i ++) { + $value_length += 0x01; + } + $value_length = chr($value_length); + + while (strlen($value_length) < 2) + $value_length = chr(0x00) . $value_length; + + $this->meta->username = chr(0x42) // keyword type || value-tag + . chr(0x00). chr(0x14) // name-length + . "requesting-user-name" + . $value_length + . $username; + + self::_putDebug( sprintf(_("Username: %s"),$username),2); + $this->setup->username = 1; + } + // }}} + + // {{{ setAuthentification ($username,$password) + public function setAuthentification ($username,$password) { + self::setAuthentication ($username,$password); + } + // }}} + + // {{{ setAuthentication ($username,$password) + public function setAuthentication ($username,$password) { + $this->password = $password; + $this->username = $username; + + self::_putDebug( _("Setting password"),2); + $this->setup->password = 1; + } + // }}} + + // {{{ setSides ($sides=2) + public function setSides ($sides=2) { + + $this->meta->sides = ''; + if (!$sides) + return true; + + switch ($sides) { + case 1: + $sides = "one-sided"; + break; + case 2: + $sides = "two-sided-long-edge"; + break; + case "2CE": + $sides = "two-sided-short-edge"; + break; + default: + $sides = $sides; // yeah, what ? + break; + } + + + $this->meta->sides = chr(0x44) // keyword type | value-tag + . chr(0x00). chr(0x05) // name-length + . "sides" // sides | name + . self::_giveMeStringLength($sides) // value-length + . $sides ; // one-sided | value + + self::_putDebug( sprintf(_("Sides value set to %s"), $sides),2); + } + // }}} + + // {{{ setFidelity () + public function setFidelity () { + + // whether the server can't replace any attributes (eg, 2 sided print is not possible, + // so print one sided) and DO NOT THE JOB. + $this->meta->fidelity = chr(0x22) // boolean type | value-tag + . chr(0x00). chr(0x16) // name-length + . "ipp-attribute-fidelity" // ipp-attribute-fidelity | name + . chr(0x00) . chr(0x01) // value-length + . chr(0x01); // true | value + + self::_putDebug( _("Fidelity attribute is set (paranoid mode)"),3); + + } + // }}} + + // {{{ unsetFidelity () + public function unsetFidelity () { + + // whether the server can replace any attributes (eg, 2 sided print is not possible, + // so print one sided) and DO THE JOB. + + $this->meta->fidelity = chr(0x22) // boolean type | value-tag + . chr(0x00). chr(0x16) // name-length + . "ipp-attribute-fidelity" // ipp-attribute-fidelity | name + . chr(0x00) . chr(0x01) // value-length + . chr(0x00); // false | value + + self::_putDebug( _("Fidelity attribute is unset"),2); + } + // }}} + + // {{{ setMessage() + public function setMessage ($message='') { + + $this->meta->message = ''; + if (!$message) + return true; + + $this->meta->message = chr(0x41) // attribute type = textWithoutLanguage + . chr(0x00) . chr(0x07) + . "message" + . self::_giveMeStringLength(substr($message,0,127)) + . substr($message,0,127); + + self::_putDebug( sprintf(_('Setting message to "%s"'),$message),2); + } + // }}} + + // {{{ setPageRanges($page_ranges) + public function setPageRanges($page_ranges) { + + // $pages_ranges = string: "1:5 10:25 40:52 ..." + // to unset, specify an empty string. + + $this->meta->page_range = ''; + + if (!$page_ranges) + return true; + + $page_ranges = trim(str_replace("-",":",$page_ranges)); + + $first = true; + $page_ranges = split(' ',$page_ranges); + foreach ($page_ranges as $page_range) { + $value = self::_rangeOfIntegerBuild($page_range); + + if ($first) + $this->meta->page_ranges .= $this->tags_types['rangeOfInteger']['tag'] + . self::_giveMeStringLength('page-ranges') + . 'page-ranges' + . self::_giveMeStringLength($value) + . $value; + else + $this->meta->page_ranges .= $this->tags_types['rangeOfInteger']['tag'] + . self::_giveMeStringLength('') + . self::_giveMeStringLength($value) + . $value; + $first = false; + } + + } + // }}} + + // {{{ setAttribute($attribute,$value) + public function setAttribute($attribute,$values) { + + $operation_attributes_tags = array_keys($this->operation_tags); + $job_attributes_tags = array_keys($this->job_tags); + $printer_attributes_tags = array_keys($this->printer_tags); + self::unsetAttribute($attribute); + + if (in_array($attribute,$operation_attributes_tags)) { + if (!is_array($values)) + self::_setOperationAttribute ($attribute,$values); + else + foreach ($values as $value) + self::_setOperationAttribute ($attribute,$value); + + } elseif (in_array($attribute,$job_attributes_tags)) { + if (!is_array($values)) + self::_setJobAttribute ($attribute,$values); + else + foreach ($values as $value) + self::_setJobAttribute ($attribute,$value); + } elseif (in_array($attribute,$printer_attributes_tags)) { + if (!is_array($values)) + self::_setPrinterAttribute ($attribute,$values); + else + foreach ($values as $value) + self::_setPrinterAttribute ($attribute,$value); + + } else { + trigger_error(sprintf(_('SetAttribute: Tag "%s" is not a printer or a job attribute'),$attribute),E_USER_NOTICE); + self::_putDebug(sprintf(_('SetAttribute: Tag "%s" is not a printer or a job attribute'),$attribute),3); + self::_errorLog(sprintf(_('SetAttribute: Tag "%s" is not a printer or a job attribute'),$attribute),2); + return FALSE; + } + + } + // }}} + + // {{{ unsetAttribute($attribute) + public function unsetAttribute($attribute) { + + $operation_attributes_tags = array_keys($this->operation_tags); + $job_attributes_tags = array_keys($this->job_tags); + $printer_attributes_tags = array_keys($this->printer_tags); + + if (in_array($attribute,$operation_attributes_tags)) + unset ($this->operation_tags[$attribute]['value'], $this->operation_tags[$attribute]['systag']); + elseif (in_array($attribute,$job_attributes_tags)) + unset ($this->job_tags[$attribute]['value'], $this->job_tags[$attribute]['systag']); + elseif (in_array($attribute,$printer_attributes_tags)) + unset ($this->printer_tags[$attribute]['value'], $this->printer_tags[$attribute]['systag']); + else { + trigger_error(sprintf(_('unsetAttribute: Tag "%s" is not a printer or a job attribute'),$attribute),E_USER_NOTICE); + self::_putDebug(sprintf(_('unsetAttribute: Tag "%s" is not a printer or a job attribute'),$attribute),3); + self::_errorLog(sprintf(_('unsetAttribute: Tag "%s" is not a printer or a job attribute'),$attribute),2); + return FALSE; + } + + return true; + } + // }}} + +// LOGGING / DEBUGGING + + // {{{ setLog ($log_destination,$destination_type='file',$level=2) + public function setLog ($log_destination,$destination_type='file',$level=2) { + + if (is_string($log_destination) && !empty($log_destination)) + $this->log_destination = $log_destination; + + switch ($destination_type) { + case 'file': + case 3: + $this->log_destination = $log_destination; + $this->log_type = 3; + break; + case 'logger': + case 0: + $this->log_destination = ''; + $this->log_type = 0; + break; + case 'e-mail': + case 1: + $this->log_destination = $log_destination; + $this->log_type = 1; + break; + } + $this->log_level = $level; + + } + // }}} + + // {{{ printDebug() + public function printDebug() { + for ($i = 0 ; $i < $this->debug_count ; $i++) + echo $this->debug[$i], "\n"; + $this->debug = array(); + $this->debug_count = 0; + } + // }}} + + // {{{ getDebug() + public function getDebug() { + $debug = ''; + for ($i = 0 ; $i < $this->debug_count ; $i++) + $debug .= $this->debug[$i]; + $this->debug = array(); + $this->debug_count = 0; + return $debug; + } + // }}} + +// OPERATIONS + + // {{{ printJob() + public function printJob(){ + // this version of printJob do not parse server output for job's attributes + + self::_putDebug( sprintf("************** Date: %s ***********", + date('Y-m-d H:i:s'))); + + if (!$this->_stringJob()) + return FALSE; + + if (is_readable($this->data)){ + self::_putDebug( _("Printing a FILE")); + + $this->output = $this->stringjob; + + if ($this->setup->datatype == "TEXT") + $this->output .= chr(0x16); + + + $post_values = array( "Content-Type" => "application/ipp", + "Data" => $this->output, + "File" => $this->data); + + if ($this->setup->datatype == "TEXT" && !isset($this->setup->noFormFeed)) + $post_values = array_merge($post_values,array("Filetype"=>"TEXT")); + + } else { + self::_putDebug( _("Printing DATA")); + + $this->output = $this->stringjob; + $this->output .= $this->datahead; + $this->output .= $this->data; + $this->output .= $this->datatail; + + $post_values = array( "Content-Type" => "application/ipp", + "Data" => $this->output); + + + } + + if (self::_sendHttp ($post_values,$this->paths["printers"])) + self::_parseServerOutput(); + + if (isset($this->serveroutput) && isset($this->serveroutput->status)) { + + $this->status = array_merge($this->status,array($this->serveroutput->status)); + + if ($this->serveroutput->status == "successfull-ok") + self::_errorLog(sprintf("printing job %s: ",$this->last_job) .$this->serveroutput->status,3); + else + self::_errorLog(sprintf("printing job: ",$this->last_job) .$this->serveroutput->status,1); + + return $this->serveroutput->status; + + } + + $this->status = array_merge($this->status,array("OPERATION FAILED")); + $this->jobs = array_merge($this->jobs,array("")); + $this->jobs_uri = array_merge($this->jobs_uri,array("")); + self::_errorLog("printing job : OPERATION FAILED",1); + + return false; + } + // }}} + + +/****************** +* +* PROTECTED FUNCTIONS +* +*******************/ + +// HTTP OUTPUT + + // {{{ _sendHttp ($post_values,$uri) + protected function _sendHttp ($post_values,$uri) { + /* + This function Copyright (C) 2005-2006 Thomas Harding, Manuel Lemos + */ + + $this->response_completed[] = "no"; + unset($this->serverouptut); + + self::_putDebug( _("Processing HTTP request"),2); + + $this->serveroutput->headers = array(); + $this->serveroutput->body = ""; + + $http = new http_class; + if (!$this->unix) + $http->host = $this->host; + else + $http->host = "localhost"; + $http->with_exceptions = $this->with_exceptions; + + + if ($this->debug_http) { + $http->debug = 1; + $http->html_debug=0; + } else { + $http->debug=0; + $http->html_debug=0; + } + + $url="http://".$this->host; + if ($this->ssl) + $url="https://".$this->host; + if ($this->unix) + $url="unix://".$this->host; + + $http->port = $this->port; + $http->timeout = $this->http_timeout; + $http->data_timeout= $this->http_data_timeout; + + $http->force_multipart_form_post = false; + + $http->user = $this->username; + $http->password = $this->password; + + $error=$http->GetRequestArguments($url,$arguments); + $arguments["RequestMethod"]="POST"; + $arguments["Headers"] = array("Content-Type" => "application/ipp"); + $arguments["BodyStream"] = array( array("Data" => $post_values["Data"]) ); + + if (isset($post_values["File"])) + $arguments["BodyStream"][]=array("File"=>$post_values["File"]); + if (isset($post_values["FileType"]) + && !strcmp($post_values["FileType"],"TEXT")) + $arguments["BodyStream"][]=array("Data"=>Chr(12)); + + $arguments["RequestURI"] = $uri; + + if ($this->with_exceptions && $this->handle_http_exceptions) + { + try + { + $error=$http->Open($arguments); + } + catch (httpException $e) + { + throw new ippException(sprintf("http error: %s", $e->getMessage()),$e->getErrno()); + } + } + else + { + $error=$http->Open($arguments); + } + + if($error=="") { + $error=$http->SendRequest($arguments); + + if($error=="") { + + self::_putDebug( "H T T P R E Q U E S T :"); + self::_putDebug("Request headers:"); + + for(Reset($http->request_headers),$header=0;$headerrequest_headers);Next($http->request_headers),$header++) { + + $header_name=Key($http->request_headers); + if(GetType($http->request_headers[$header_name])=="array") { + for($header_value=0;$header_valuerequest_headers[$header_name]);$header_value++) + self::_putDebug( $header_name.": ".$http->request_headers[$header_name][$header_value]); + } else + self::_putDebug( $header_name.": ".$http->request_headers[$header_name]); + + } + self::_putDebug( "Request body:"); + self::_putDebug( htmlspecialchars($http->request_body) + ."*********** END REQUEST BODY *********"); + + + $i = 0; + $headers=array(); + unset($this->serveroutput->headers); + $error=$http->ReadReplyHeaders($headers); + + self::_putDebug( "H T T P R E S P O N S E :"); + if($error=="") { + + self::_putDebug("Response headers:"); + for(Reset($headers),$header=0;$headerserveroutput->headers[$i] = $header_name.": ".$headers[$header_name][$header_value]; + $i++; + } + } else { + self::_putDebug( $header_name.": ".$headers[$header_name]); + $this->serveroutput->headers[$i] = $header_name.": ".$headers[$header_name]; + $i++; + } + } + + self::_putDebug( "\n\nResponse body:\n"); + $this->serveroutput->body = ""; + for(;;) { + $error=$http->ReadReplyBody($body,1024); + if($error!="" || strlen($body)==0) + break; + self::_putDebug(htmlentities($body)); + $this->serveroutput->body .= $body; + } + } + self::_putDebug( "********* END RESPONSE BODY ********"); + } + } + $http->Close(); + if(strlen($error)) { + self::_putDebug($error,4); + if ($this->with_exceptions) { + $this->serveroutput->status = $error; + throw new ippException($error); + } + trigger_error($error,E_USER_WARNING); + $this->serveroutput->status = $error; + return FALSE; + } + return true; + } + // }}} + +// INIT + + // {{{ _initTags () + protected function _initTags () { + + $this->tags_types = array ( "unsupported" => array ("tag" => chr(0x10), + "build" => ""), + "reserved" => array ("tag" => chr(0x11), + "build" => ""), + "unknown" => array ("tag" => chr(0x12), + "build" => ""), + "no-value" => array ("tag" => chr(0x13), + "build" => "no_value"), + "integer" => array ("tag" => chr(0x21), + "build" => "integer"), + "boolean" => array ("tag" => chr(0x22), + "build" => "boolean"), + "enum" => array ("tag" => chr(0x23), + "build" => "enum"), + "octetString" => array ("tag" => chr(0x30), + "build" => "octet_string"), + "datetime" => array ("tag" => chr(0x31), + "build" => "datetime"), + "resolution" => array ("tag" => chr(0x32), + "build" => "resolution"), + "rangeOfInteger" => array ("tag" => chr(0x33), + "build" => "range_of_integers"), + "textWithLanguage" => array ("tag" => chr(0x35), + "build" => "string"), + "nameWithLanguage" => array ("tag" => chr(0x36), + "build" => "string"), + /* + "text" => array ("tag" => chr(0x40), + "build" => "string"), + "text string" => array ("tag" => chr(0x40), + "build" => "string"), + */ + "textWithoutLanguage" => array ("tag" => chr(0x41), + "build" => "string"), + "nameWithoutLanguage" => array ("tag" => chr(0x42), + "buid" => "string"), + "keyword" => array ("tag" => chr(0x44), + "build" => "string"), + "uri" => array ("tag" => chr(0x45), + "build" => "string"), + "uriScheme" => array ("tag" => chr(0x46), + "build" => "string"), + "charset" => array ("tag" => chr(0x47), + "build" => "string"), + "naturalLanguage" => array ("tag" => chr(0x48), + "build" => "string"), + "mimeMediaType" => array ("tag" => chr(0x49), + "build" => "string"), + "extendedAttributes" => array ("tag" => chr(0x7F), + "build" => "extended"), + ); + + + $this->operation_tags = array ("compression" => array("tag" => "keyword"), + "document-natural-language" => array("tag" => "naturalLanguage"), + "job-k-octets" => array("tag" => "integer"), + "job-impressions" => array("tag" => "integer"), + "job-media-sheets" => array("tag" => "integer"), + ); + + $this->job_tags = array ( "job-priority" => array("tag" => "integer"), + "job-hold-until" => array("tag" => "keyword"), + "job-sheets" => array("tag" => "keyword"), //banner page + "multiple-document-handling" => array("tag" => "keyword"), + //"copies" => array("tag" => "integer"), + "finishings" => array("tag" => "enum"), + //"page-ranges" => array("tag" => "rangeOfInteger"), // has its own function + //"sides" => array("tag" => "keyword"), // has its own function + "number-up" => array("tag" => "integer"), + "orientation-requested" => array("tag" => "enum"), + "media" => array("tag" => "keyword"), + "printer-resolution" => array("tag" => "resolution"), + "print-quality" => array("tag" => "enum"), + "job-message-from-operator" => array("tag" => "textWithoutLanguage"), + ); + + $this->printer_tags = array ( "requested-attributes" => array("tag" => "keyword")); + } + // }}} + +// SETUP + + // {{{ _setOperationId () + protected function _setOperationId () { + $prepend = ''; + $this->operation_id += 1; + $this->meta->operation_id = self::_integerBuild($this->operation_id); + self::_putDebug( "operation id is: ".$this->operation_id,2); + } + // }}} + + // {{{ _setJobId() + protected function _setJobId() { + + $this->meta->jobid +=1; + $prepend = ''; + $prepend_length = 4 - strlen($this->meta->jobid); + for ($i = 0; $i < $prepend_length ; $i++ ) + $prepend .= '0'; + + return $prepend.$this->meta->jobid; + } + // }}} + + // {{{ _setJobUri ($job_uri) + protected function _setJobUri ($job_uri) { + + $this->meta->job_uri = chr(0x45) // type uri + . chr(0x00).chr(0x07) // name-length + . "job-uri" + //. chr(0x00).chr(strlen($job_uri)) + . self::_giveMeStringLength($job_uri) + . $job_uri; + + self::_putDebug( "job-uri is: ".$job_uri,2); + } + // }}} + +// RESPONSE PARSING + + // {{{ _parseServerOutput () + protected function _parseServerOutput () { + + $this->serveroutput->response = array(); + + if (!self::_parseHttpHeaders ()) return FALSE; + + $this->_parsing->offset = 0; + + self::_parseIppVersion (); + self::_parseStatusCode (); + self::_parseRequestID (); + $this->_parseResponse (); + + //devel + self::_putDebug( sprintf("***** IPP STATUS: %s ******",$this->serveroutput->status),4); + self::_putDebug( "****** END OF OPERATION ****"); + + return true; + } + // }}} + + // {{{ _parseHttpHeaders + protected function _parseHttpHeaders () { + + $response = ""; + + switch ($this->serveroutput->headers[0]) { + + case "http/1.1 200 ok: ": + $this->serveroutput->httpstatus = "HTTP/1.1 200 OK"; + $response = "OK"; + break; + case "http/1.1 100 continue: ": + $this->serveroutput->httpstatus = "HTTP/1.1 100 CONTINUE"; + $response = "OK"; + break; + case "": + $this->serveroutput->httpstatus = "HTTP/1.1 000 No Response From Server"; + $this->serveroutput->status = "HTTP-ERROR-000_NO_RESPONSE_FROM_SERVER"; + trigger_error("No Response From Server",E_USER_WARNING); + self::_errorLog("No Response From Server",1); + $this->disconnected = 1; + return FALSE; + break; + default: + $server_response = preg_replace("/: $/",'',$this->serveroutput->headers[0]); + $strings = split(' ',$server_response,3); + $errno = $strings[1]; + $string = strtoupper(str_replace(' ','_',$strings[2])); + trigger_error(sprintf(_("server responds %s"),$server_response),E_USER_WARNING); + self::_errorLog("server responds ".$server_response,1); + $this->serveroutput->httpstatus = strtoupper($strings[0])." ".$errno." ".ucfirst($strings[2]); + $this->serveroutput->status = "HTTP-ERROR-".$errno."-".$string; + $this->disconnected = 1; + return FALSE; + break; + } + + unset ($this->serveroutput->headers); + + return TRUE; + } + // }}} + + // {{{ _parseIppVersion () + protected function _parseIppVersion () { + + $ippversion = (ord($this->serveroutput->body[ $this->_parsing->offset]) * 256) + + ord($this->serveroutput->body[$this->_parsing->offset + 1]); + + switch($ippversion) { + case 0x0101: + $this->serveroutput->ipp_version = "1.1"; + break; + default: + $this->serveroutput->ipp_version = sprintf("%u.%u (Unknown)",ord($this->serveroutput->body[ $this->_parsing->offset]) * 256,ord($this->serveroutput->body[$this->_parsing->offset + 1])); + break; + } + + self::_putDebug( "I P P R E S P O N S E :\n\n"); + self::_putDebug( sprintf("IPP version %s%s: %s", + ord($this->serveroutput->body[ $this->_parsing->offset]), + ord($this->serveroutput->body[$this->_parsing->offset + 1]), + $this->serveroutput->ipp_version)); + + $this->_parsing->offset += 2; + return; + } + // }}} + + // {{{ _parseStatusCode () + protected function _parseStatusCode () { + $status_code = (ord($this->serveroutput->body[$this->_parsing->offset]) * 256) + + ord($this->serveroutput->body[$this->_parsing->offset + 1]); + + + $this->serveroutput->status ="NOT PARSED"; + + $this->_parsing->offset += 2; + + if (strlen($this->serveroutput->body) < $this->_parsing->offset) + return false; + + + if ($status_code < 0x00FF) { + $this->serveroutput->status = "successfull"; + } elseif ($status_code < 0x01FF) { + $this->serveroutput->status = "informational"; + } elseif ($status_code < 0x02FF) { + $this->serveroutput->status = "redirection"; + } elseif ($status_code < 0x04FF) { + $this->serveroutput->status = "client-error"; + } elseif ($status_code < 0x05FF) { + $this->serveroutput->status = "server-error"; + } + + switch ($status_code) { + case 0x0000: + $this->serveroutput->status = "successfull-ok"; + break; + case 0x0001: + $this->serveroutput->status = "successful-ok-ignored-or-substituted-attributes"; + break; + case 0x002: + $this->serveroutput->status = "successful-ok-conflicting-attributes"; + break; + case 0x0400: + $this->serveroutput->status = "client-error-bad-request"; + break; + case 0x0401: + $this->serveroutput->status = "client-error-forbidden"; + break; + case 0x0402: + $this->serveroutput->status = "client-error-not-authenticated"; + break; + case 0x0403: + $this->serveroutput->status = "client-error-not-authorized"; + break; + case 0x0404: + $this->serveroutput->status = "client-error-not-possible"; + break; + case 0x0405: + $this->serveroutput->status = "client-error-timeout"; + break; + case 0x0406: + $this->serveroutput->status = "client-error-not-found"; + break; + case 0x0407: + $this->serveroutput->status = "client-error-gone"; + break; + case 0x0408: + $this->serveroutput->status = "client-error-request-entity-too-large"; + break; + case 0x0409: + $this->serveroutput->status = "client-error-request-value-too-long"; + break; + case 0x040A: + $this->serveroutput->status = "client-error-document-format-not-supported"; + break; + case 0x040B: + $this->serveroutput->status = "client-error-attributes-or-values-not-supported"; + break; + case 0x040C: + $this->serveroutput->status = "client-error-uri-scheme-not-supported"; + break; + case 0x040D: + $this->serveroutput->status = "client-error-charset-not-supported"; + break; + case 0x040E: + $this->serveroutput->status = "client-error-conflicting-attributes"; + break; + case 0x040F: + $this->serveroutput->status = "client-error-compression-not-supported"; + break; + case 0x0410: + $this->serveroutput->status = "client-error-compression-error"; + break; + case 0x0411: + $this->serveroutput->status = "client-error-document-format-error"; + break; + case 0x0412: + $this->serveroutput->status = "client-error-document-access-error"; + break; + case 0x0413: // RFC3380 + $this->serveroutput->status = "client-error-attributes-not-settable"; + break; + case 0x0500: + $this->serveroutput->status = "server-error-internal-error"; + break; + case 0x0501: + $this->serveroutput->status = "server-error-operation-not-supported"; + break; + case 0x0502: + $this->serveroutput->status = "server-error-service-unavailable"; + break; + case 0x0503: + $this->serveroutput->status = "server-error-version-not-supported"; + break; + case 0x0504: + $this->serveroutput->status = "server-error-device-error"; + break; + case 0x0505: + $this->serveroutput->status = "server-error-temporary-error"; + break; + case 0x0506: + $this->serveroutput->status = "server-error-not-accepting-jobs"; + break; + case 0x0507: + $this->serveroutput->status = "server-error-busy"; + break; + case 0x0508: + $this->serveroutput->status = "server-error-job-canceled"; + break; + case 0x0509: + $this->serveroutput->status = "server-error-multiple-document-jobs-not-supported"; + break; + default: + break; + } + + + self::_putDebug( sprintf("status-code: %s%s: %s ",$this->serveroutput->body[$this->_parsing->offset], + $this->serveroutput->body[$this->_parsing->offset + 1], + $this->serveroutput->status),4); + + return; + } + // }}} + + // {{{ _parseRequestID () + protected function _parseRequestID () { + + $this->serveroutput->request_id = self::_interpretInteger(substr($this->serveroutput->body,$this->_parsing->offset,4)); + self::_putDebug( "request-id ". $this->serveroutput->request_id,2); + $this->_parsing->offset += 4; + + return; + } + // }}} + + // {{{ _interpretInteger($value) + protected function _interpretInteger($value) { + + // they are _signed_ integers + $value_parsed = 0; + + for ($i = strlen($value) ; $i > 0 ; $i --) + $value_parsed += (1 << (($i - 1)*8)) * ord($value[strlen($value) - $i]); + if ($value_parsed >= 2147483648) + $value_parsed -= 4294967296; + return $value_parsed; + } + // }}} + + // {{{ _parseResponse () {} + protected function _parseResponse () {} + // }}} +// REQUEST BUILDING + + // {{{ _stringJob () + protected function _stringJob () { + + if (!isset($this->setup->charset)) + self::setCharset('us-ascii'); + if (!isset($this->setup->datatype)) + self::setBinary(); + + if (!isset($this->setup->uri)) { + $this->getPrinters(); + unset($this->jobs[count($this->jobs) - 1]); + unset($this->jobs_uri[count($this->jobs_uri) - 1]); + unset($this->status[count($this->status) - 1]); + + if (array_key_exists(0,$this->available_printers)) + self::setPrinterURI($this->available_printers[0]); + else { + trigger_error(_("_stringJob: Printer URI is not set: die"),E_USER_WARNING); + self::_putDebug( _("_stringJob: Printer URI is not set: die"),4); + self::_errorLog(" Printer URI is not set, die",2); + return FALSE; + } + } + + if (!isset($this->setup->copies)) + self::setCopies(1); + if (!isset($this->setup->language)) + self::setLanguage('en_us'); + + if (!isset($this->setup->mime_media_type)) + self::setMimeMediaType(); + if ($this->setup->datatype != "TEXT") + unset ($this->setup->mime_media_type); + + if (!isset($this->setup->jobname)) + self::setJobName(); + unset($this->setup->jobname); + + if (!isset($this->meta->username)) + self::setUserName(); + + if (!isset($this->meta->fidelity)) + $this->meta->fidelity = ''; + + if (!isset($this->meta->document_name)) + $this->meta->document_name = ''; + + if (!isset($this->meta->sides)) + $this->meta->sides = ''; + + if (!isset($this->meta->page_ranges)) + $this->meta->page_ranges = ''; + + $jobattributes = ''; + $operationattributes = ''; + $printerattributes = ''; + $this->_buildValues($operationattributes,$jobattributes,$printerattributes); + self::_setOperationId(); + + if (!isset($this->error_generation->request_body_malformed)) + $this->error_generation->request_body_malformed = ""; + + $this->stringjob = chr(0x01) . chr(0x01) // 1.1 | version-number + . chr(0x00) . chr (0x02) // Print-Job | operation-id + . $this->meta->operation_id // request-id + . chr(0x01) // start operation-attributes | operation-attributes-tag + . $this->meta->charset + . $this->meta->language + . $this->meta->printer_uri + . $this->meta->username + . $this->meta->jobname + . $this->meta->fidelity + . $this->meta->document_name + . $this->meta->mime_media_type + . $operationattributes; + if ($this->meta->copies + || $this->meta->sides + || $this->meta->page_ranges + || !empty($jobattributes)) + { + $this->stringjob .= chr(0x02) // start job-attributes | job-attributes-tag + . $this->meta->copies + . $this->meta->sides + . $this->meta->page_ranges + . $jobattributes; + } + $this->stringjob .= chr(0x03); // end-of-attributes | end-of-attributes-tag + + self::_putDebug( sprintf(_("String sent to the server is: %s"), $this->stringjob)); + return TRUE; + } + // }}} + + // {{{ _buildValues (&$operationattributes,&$jobattributes); + protected function _buildValues (&$operationattributes,&$jobattributes,&$printerattributes) { + + $operationattributes = ''; + foreach ($this->operation_tags as $key => $values) { + $item = 0; + if (array_key_exists('value',$values)) + foreach ($values['value'] as $item_value) { + if ($item == 0) + $operationattributes .= $values['systag'] + . self::_giveMeStringLength($key) + . $key + . self::_giveMeStringLength($item_value) + . $item_value; + else + $operationattributes .= $values['systag'] + . self::_giveMeStringLength('') + . self::_giveMeStringLength($item_value) + . $item_value; + + $item++; + } + } + + $jobattributes = ''; + foreach ($this->job_tags as $key => $values) + { + $item = 0; + if (array_key_exists('value',$values)) + { + foreach ($values['value'] as $item_value) { + if ($item == 0) + $jobattributes .= $values['systag'] + . self::_giveMeStringLength($key) + . $key + . self::_giveMeStringLength($item_value) + . $item_value; + else + $jobattributes .= $values['systag'] + . self::_giveMeStringLength('') + . self::_giveMeStringLength($item_value) + . $item_value; + + $item++; + } + } + } + + $printerattributes = ''; + foreach ($this->printer_tags as $key => $values) { + $item = 0; + if (array_key_exists('value',$values)) + foreach ($values['value'] as $item_value) { + if ($item == 0) + $printerattributes .= $values['systag'] + . self::_giveMeStringLength($key) + . $key + . self::_giveMeStringLength($item_value) + . $item_value; + else + $printerattributes .= $values['systag'] + . self::_giveMeStringLength('') + . self::_giveMeStringLength($item_value) + . $item_value; + + $item++; + } + } + + reset ($this->job_tags); + reset ($this->operation_tags); + reset ($this->printer_tags); + return true; + } + // }}} + + // {{{ _giveMeStringLength ($string) + protected function _giveMeStringLength ($string) { + + $prepend = ''; + $length = strlen($string); + $lengthlength = strlen(chr($length)); + while ($lengthlength < 2) { + $prepend .= chr(0x00); + $lengthlength += 1; + } + $length = $prepend . chr($length); + + return $length; + } + // }}} + + // {{{ _enumBuild ($tag,$value) + protected function _enumBuild ($tag,$value) { + + switch ($tag) { + case "orientation-requested": + switch ($value) { + case 'portrait': + $value = chr(3); + break; + case 'landscape': + $value = chr(4); + break; + case 'reverse-landscape': + $value = chr(5); + break; + case 'reverse-portrait': + $value = chr(6); + break; + } + break; + case "print-quality": + switch($value) { + case 'draft': + $value = chr(3); + break; + case 'normal': + $value = chr(4); + break; + case 'high': + $value = chr(5); + break; + } + break; + case "finishing": + switch ($value) { + case 'none': + $value = chr(3); + break; + case 'staple': + $value = chr(4); + break; + case 'punch': + $value = chr(5); + break; + case 'cover': + $value = chr(6); + break; + case 'bind': + $value = chr(7); + break; + case 'saddle-stitch': + $value = chr(8); + break; + case 'edge-stitch': + $value = chr(9); + break; + case 'staple-top-left': + $value = chr(20); + break; + case 'staple-bottom-left': + $value = chr(21); + break; + case 'staple-top-right': + $value = chr(22); + break; + case 'staple-bottom-right': + $value = chr(23); + break; + case 'edge-stitch-left': + $value = chr(24); + break; + case 'edge-stitch-top': + $value = chr(25); + break; + case 'edge-stitch-right': + $value = chr(26); + break; + case 'edge-stitch-bottom': + $value = chr(27); + break; + case 'staple-dual-left': + $value = chr(28); + break; + case 'staple-dual-top': + $value = chr(29); + break; + case 'staple-dual-right': + $value = chr(30); + break; + case 'staple-dual-bottom': + $value = chr(31); + break; + } + break; + } + + $prepend = ''; + while ((strlen($value) + strlen($prepend)) < 4) + $prepend .= chr(0); + + return $prepend.$value; + } + // }}} + + // {{{ _integerBuild ($integer) + protected function _integerBuild ($value) { + + if ($value >= 2147483647 || $value < -2147483648) { + trigger_error(_("Values must be between -2147483648 and 2147483647: assuming '0'"),E_USER_WARNING); + return chr(0x00).chr(0x00).chr(0x00).chr(0x00); + } + + $initial_value = $value; + + $int1 = $value & 0xFF; + $value -= $int1; + $value = $value >> 8; + $int2 = $value & 0xFF; + $value -= $int2; + $value = $value >> 8; + $int3 = $value & 0xFF; + $value -= $int3; + $value = $value >> 8; + $int4 = $value & 0xFF; //64bits + + if ($initial_value < 0) + $int4 = chr($int4) | chr(0x80); + else + $int4 = chr($int4); + + $value = $int4.chr($int3).chr($int2).chr($int1); + + return $value; + } + // }}} + + // {{{ _rangeOfIntegerBuild ($integers) + protected function _rangeOfIntegerBuild ($integers) { + + $integers = split(":",$integers); + + for ($i = 0 ; $i < 2 ; $i++) + $outvalue[$i] = self::_integerBuild($integers[$i]); + + return $outvalue[0].$outvalue[1]; + } + // }}} + + // {{{ _setJobAttribute ($attribute,$value) + protected function _setJobAttribute ($attribute,$value) { + //used by setAttribute + + $tag_type = $this->job_tags[$attribute]['tag']; + switch ($tag_type) { + case 'integer': + $this->job_tags[$attribute]['value'][] = self::_integerBuild($value); + break; + case 'nameWithoutLanguage': + case 'nameWithLanguage': + case 'textWithoutLanguage': + case 'textWithLanguage': + case 'keyword': + case 'naturalLanguage': + $this->job_tags[$attribute]['value'][] = $value; + break; + case 'enum': + $value = $this->_enumBuild($attribute,$value); // may be overwritten by children + $this->job_tags[$attribute]['value'][] = $value; + break; + case 'rangeOfInteger': + // $value have to be: INT1:INT2 , eg 100:1000 + $this->job_tags[$attribute]['value'][] = self::_rangeOfIntegerBuild($value); + break; + case 'resolution': + if (preg_match("#dpi#",$value)) $unit = chr(0x3); + if (preg_match("#dpc#",$value)) $unit = chr(0x4); + $search = array("#(dpi|dpc)#",'#(x|-)#'); + $replace = array("",":"); + $value = self::_rangeOfIntegerBuild(preg_replace($search,$replace,$value)).$unit; + $this->job_tags[$attribute]['value'][] = $value; + break; + default: + trigger_error(sprintf(_('SetAttribute: Tag "%s": cannot set attribute'),$attribute),E_USER_NOTICE); + self::_putDebug(sprintf(_('SetAttribute: Tag "%s": cannot set attribute'),$attribute),2); + self::_errorLog(sprintf(_('SetAttribute: Tag "%s": cannot set attribute'),$attribute),2); + return FALSE; + break; + } + $this->job_tags[$attribute]['systag'] = $this->tags_types[$tag_type]['tag']; + + } + // }}} + + // {{{ _setOperationAttribute ($attribute,$value) + protected function _setOperationAttribute ($attribute,$value) { + //used by setAttribute + $tag_type = $this->operation_tags[$attribute]['tag']; + switch ($tag_type) { + case 'integer': + $this->operation_tags[$attribute]['value'][] = self::_integerBuild($value); + break; + case 'keyword': + case 'naturalLanguage': + $this->operation_tags[$attribute]['value'][] = $value; + break; + default: + trigger_error(sprintf(_('SetAttribute: Tag "%s": cannot set attribute'),$attribute),E_USER_NOTICE); + self::_putDebug(sprintf(_('SetAttribute: Tag "%s": cannot set attribute'),$attribute),2); + self::_errorLog(sprintf(_('SetAttribute: Tag "%s": cannot set attribute'),$attribute),2); + return FALSE; + break; + } + $this->operation_tags[$attribute]['systag'] = $this->tags_types[$tag_type]['tag']; + + } + // }}} + + // {{{ _setPrinterAttribute ($attribute,$value) + protected function _setPrinterAttribute ($attribute,$value) { + //used by setAttribute + $tag_type = $this->printer_tags[$attribute]['tag']; + switch ($tag_type) { + case 'integer': + $this->printer_tags[$attribute]['value'][] = self::_integerBuild($value); + break; + case 'keyword': + case 'naturalLanguage': + $this->printer_tags[$attribute]['value'][] = $value; + break; + default: + trigger_error(sprintf(_('SetAttribute: Tag "%s": cannot set attribute'),$attribute),E_USER_NOTICE); + self::_putDebug(sprintf(_('SetAttribute: Tag "%s": cannot set attribute'),$attribute),2); + self::_errorLog(sprintf(_('SetAttribute: Tag "%s": cannot set attribute'),$attribute),2); + return FALSE; + break; + } + $this->printer_tags[$attribute]['systag'] = $this->tags_types[$tag_type]['tag']; + + } + // }}} +// DEBUGGING + + // {{{ _putDebug($string,$level) + protected function _putDebug($string,$level=1) { + if ($level === false) + return; + if ($level < $this->debug_level) + return; + $this->debug[$this->debug_count] = substr($string,0,1024); + $this->debug_count ++; + //$this->debug .= substr($string,0,1024); + } + // }}} + +// LOGGING + + // {{{ _errorLog($log,$level) + protected function _errorLog($string_to_log,$level) { + + if ($level < $this->log_level) + return; + + $string = sprintf('%s : %s:%s user %s : %s', + basename($_SERVER['PHP_SELF']), + $this->host, + $this->port, + $this->requesting_user, + $string_to_log); + + if ($this->log_type == 0) { + error_log($string); + return; + } + + $string = sprintf("%s %s Host %s:%s user %s : %s\n", + date('M d H:i:s'), + basename($_SERVER['PHP_SELF']), + $this->host, + $this->port, + $this->requesting_user, + $string_to_log); + error_log($string,$this->log_type,$this->log_destination); + + return; + } + // }}} + +}; + +/* + * Local variables: + * mode: php + * tab-width: 4 + * c-basic-offset: 4 + * End: + */ +?> diff --git a/Moodle/mod/print/CupsPrintIPP.php b/Moodle/mod/print/CupsPrintIPP.php new file mode 100755 index 0000000..a7e5a30 --- /dev/null +++ b/Moodle/mod/print/CupsPrintIPP.php @@ -0,0 +1,671 @@ +jobs = array_merge($this->jobs,array("")); + $this->jobs_uri = array_merge($this->jobs_uri,array("")); + $this->parsed = array(); + unset($this->printer_attributes); + + if (!isset($this->setup->charset)) + self::setCharset('us-ascii'); + + if (!isset($this->setup->language)) + self::setLanguage('en'); + + self::_setOperationId(); + + for($i = 0 ; $i < count($attributes) ; $i++) + if ($i == 0) + $this->meta->attributes = chr(0x44) // Keyword + . self::_giveMeStringLength('requested-attributes') + . 'requested-attributes' + . self::_giveMeStringLength($attributes[0]) + . $attributes[0]; + else + $this->meta->attributes .= chr(0x44) // Keyword + . chr(0x0).chr(0x0) // zero-length name + . self::_giveMeStringLength($attributes[$i]) + . $attributes[$i]; + + $this->stringjob = chr(0x01) . chr(0x01) // IPP version 1.1 + . chr(0x40). chr(0x01) // operation: cups vendor extension: get defaults + . $this->meta->operation_id // request-id + . chr(0x01) // start operation-attributes | operation-attributes-tag + . $this->meta->charset + . $this->meta->language + . $this->meta->attributes + . chr(0x03); // end operations attribute + + $this->output = $this->stringjob; + + self::_putDebug("Request: ".$this->output); + + $post_values = array( "Content-Type" => "application/ipp", + "Data" => $this->output); + + if (self::_sendHttp ($post_values,'/')) { + + if(self::_parseServerOutput()) + self::_parsePrinterAttributes(); + } + + $this->attributes = &$this->printer_attributes; + + if (isset($this->printer_attributes->printer_type)) { + $printer_type = $this->printer_attributes->printer_type->_value0; + $table = self::_interpretPrinterType($printer_type); + + for($i = 0 ; $i < count($table) ; $i++ ) { + $index = '_value'.$i; + $this->printer_attributes->printer_type->$index = $table[$i]; + } + + } + + if (isset($this->serveroutput) && isset($this->serveroutput->status)) { + + $this->status = array_merge($this->status,array($this->serveroutput->status)); + if ($this->serveroutput->status == "successfull-ok") + self::_errorLog("getting defaults: ".$this->serveroutput->status,3); + else + self::_errorLog("getting defaults: ".$this->serveroutput->status,1); + + return $this->serveroutput->status; + + } else { + $this->status = array_merge($this->status,array("OPERATION FAILED")); + self::_errorLog("getting defaults : OPERATION FAILED",1); + } + return false; + } + // }}} + + // {{{ cupsAcceptJobs ($printer_uri) + public function cupsAcceptJobs($printer_uri) { + //The CUPS-Get-Default operation returns the default printer URI and attributes + + $this->jobs = array_merge($this->jobs,array("")); + $this->jobs_uri = array_merge($this->jobs_uri,array("")); + $this->parsed = array(); + unset($this->printer_attributes); + + if (!isset($this->setup->charset)) + self::setCharset('us-ascii'); + + if (!isset($this->setup->language)) + self::setLanguage('en'); + + self::_setOperationId(); + + $this->stringjob = chr(0x01) . chr(0x01) // IPP version 1.1 + . chr(0x40). chr(0x08) // operation: cups vendor extension: Accept-Jobs + . $this->meta->operation_id // request-id + . chr(0x01) // start operation-attributes | operation-attributes-tag + . $this->meta->charset + . $this->meta->language + . chr(0x45) // uri + . self::_giveMeStringLength('printer-uri') + . 'printer-uri' + . self::_giveMeStringLength($printer_uri) + . $printer_uri + . chr(0x03); // end operations attribute + + $this->output = $this->stringjob; + + self::_putDebug("Request: ".$this->output); + + $post_values = array( "Content-Type" => "application/ipp", + "Data" => $this->output); + + if (self::_sendHttp ($post_values,'/admin/')) { + + if(self::_parseServerOutput()) + self::_parseAttributes(); + } + + if (isset($this->serveroutput) && isset($this->serveroutput->status)) { + + $this->status = array_merge($this->status,array($this->serveroutput->status)); + if ($this->serveroutput->status == "successfull-ok") + self::_errorLog("getting defaults: ".$this->serveroutput->status,3); + else + self::_errorLog("getting defaults: ".$this->serveroutput->status,1); + + return $this->serveroutput->status; + + } else { + $this->status = array_merge($this->status,array("OPERATION FAILED")); + self::_errorLog("getting defaults : OPERATION FAILED",1); + } + return false; + } + // }}} + + // {{{ cupsRejectJobs ($printer_uri,$printer_state_message=false) + public function cupsRejectJobs($printer_uri,$printer_state_message) { + //The CUPS-Get-Default operation returns the default printer URI and attributes + + $this->jobs = array_merge($this->jobs,array("")); + $this->jobs_uri = array_merge($this->jobs_uri,array("")); + $this->parsed = array(); + unset($this->attributes); + + if (!isset($this->setup->charset)) + self::setCharset('us-ascii'); + + if (!isset($this->setup->language)) + self::setLanguage('en'); + + self::_setOperationId(); + + $message = ""; + if ($printer_state_message) + $message = chr(0x04) // start printer-attributes + . chr(0x41) // textWithoutLanguage + . self::_giveMeStringLength("printer-state-message") + . "printer-state-message" + . self::_giveMeStringLength($printer_state_message) + . $printer_state_message; + + $this->stringjob = chr(0x01) . chr(0x01) // IPP version 1.1 + . chr(0x40). chr(0x09) // operation: cups vendor extension: Reject-Jobs + . $this->meta->operation_id // request-id + . chr(0x01) // start operation-attributes | operation-attributes-tag + . $this->meta->charset + . $this->meta->language + . chr(0x45) // uri + . self::_giveMeStringLength('printer-uri') + . 'printer-uri' + . self::_giveMeStringLength($printer_uri) + . $printer_uri + . $message + . chr(0x03); // end operations attribute + + $this->output = $this->stringjob; + + self::_putDebug("Request: ".$this->output); + + $post_values = array( "Content-Type" => "application/ipp", + "Data" => $this->output); + + if (self::_sendHttp ($post_values,'/admin/')) { + + if(self::_parseServerOutput()) + self::_parseAttributes(); + } + + if (isset($this->serveroutput) && isset($this->serveroutput->status)) { + + $this->status = array_merge($this->status,array($this->serveroutput->status)); + if ($this->serveroutput->status == "successfull-ok") + self::_errorLog("getting defaults: ".$this->serveroutput->status,3); + else + self::_errorLog("getting defaults: ".$this->serveroutput->status,1); + + return $this->serveroutput->status; + + } else { + $this->status = array_merge($this->status,array("OPERATION FAILED")); + self::_errorLog("getting defaults : OPERATION FAILED",1); + } + return false; + } + // }}} + + // {{{ getPrinters() + public function getPrinters($printer_location=false,$printer_info=false,$attributes=array()) { + + if (count($attributes) == 0) + true; + $attributes=array('printer-uri-supported','printer-location','printer-info','printer-type','color-supported'); + $this->jobs = array_merge($this->jobs,array("")); + $this->jobs_uri = array_merge($this->jobs_uri,array("")); + + unset ($this->printers_attributes); + + if (!isset($this->setup->charset)) + self::setCharset('us-ascii'); + + if (!isset($this->setup->language)) + self::setLanguage('en-us'); + + self::_setOperationId(); + + $this->meta->attributes=''; + + if ($printer_location) + $this->meta->attributes .= chr(0x41) // textWithoutLanguage + . self::_giveMeStringLength('printer-location') + . 'printer-location' + . self::_giveMeStringLength($printer_location) + . $printer_location; + + + if ($printer_info) + $this->meta->attributes .= chr(0x41) // textWithoutLanguage + . self::_giveMeStringLength('printer-info') + . 'printer-info' + . self::_giveMeStringLength($printer_info) + . $printer_info; + + for($i = 0 ; $i < count($attributes) ; $i++) + if ($i == 0) + $this->meta->attributes .= chr(0x44) // Keyword + . self::_giveMeStringLength('requested-attributes') + . 'requested-attributes' + . self::_giveMeStringLength($attributes[0]) + . $attributes[0]; + else + $this->meta->attributes .= chr(0x44) // Keyword + . chr(0x0).chr(0x0) // zero-length name + . self::_giveMeStringLength($attributes[$i]) + . $attributes[$i]; + + + $this->stringjob = chr(0x01) . chr(0x01) // IPP version 1.1 + . chr(0x40). chr(0x02) // operation: cups vendor extension: get printers + . $this->meta->operation_id // request-id + . chr(0x01) // start operation-attributes | operation-attributes-tag + . $this->meta->charset + . $this->meta->language + . $this->meta->attributes + . chr(0x03); // end operations attribute + + $this->output = $this->stringjob; + + $post_values = array( "Content-Type" => "application/ipp", + "Data" => $this->output); + + if (self::_sendHttp ($post_values,'/')) { + + if(self::_parseServerOutput()) + $this->_getAvailablePrinters(); + + } + + if (isset($this->serveroutput) && isset($this->serveroutput->status)) { + + $this->status = array_merge($this->status,array($this->serveroutput->status)); + if ($this->serveroutput->status == "successfull-ok") + self::_errorLog("getting printers: ".$this->serveroutput->status,3); + else + self::_errorLog("getting printers: ".$this->serveroutput->status,1); + return $this->serveroutput->status; + + } else { + $this->status = array_merge($this->status,array("OPERATION FAILED")); + self::_errorLog("getting printers : OPERATION FAILED",1); + } + return false; + } + // }}} + + // {{{ cupsGetPrinters () + public function cupsGetPrinters () { + // alias for getPrinters(); + self::getPrinters(); + } + // }}} + + // {{{ getPrinterAttributes() + public function getPrinterAttributes() { + // complete informations from parent with Cups-specific stuff + + if(!$result = parent::getPrinterAttributes()) + return FALSE; + if(!isset($this->printer_attributes)) + return FALSE; + + if (isset ($this->printer_attributes->printer_type)) { + $printer_type = $this->printer_attributes->printer_type->_value0; + $table = self::_interpretPrinterType($printer_type); + + for($i = 0 ; $i < count($table) ; $i++ ) { + $index = '_value'.$i; + $this->printer_attributes->printer_type->$index = $table[$i]; + } + } + + return $result; + } + // }}} + +// +// SETUP +// + + // {{{ _initTags () + protected function _initTags () { + + // override parent with specific cups attributes + + $operation_tags = array (); + $this->operation_tags = array_merge ($this->operation_tags, $operation_tags); + + $job_tags = array ( "job-billing" => array("tag" => "textWithoutLanguage"), + "blackplot" => array("tag" => "boolean"), + "brightness" => array("tag" => "integer"), + "columns" => array("tag" => "integer"), + "cpi" => array("tag" => "enum"), + "fitplot" => array("tag" => "boolean"), + "gamma" => array("tag" => "integer"), + "hue" => array("tag" => "integer"), + "lpi" => array("tag" => "enum"), + "mirror" => array("tag","boolean"), + "natural-scaling" => array("tag" => "integer"), + "number-up-layout" => array("tag" => "keyword"), + "page-border" => array("tag" => "keyword"), + "page-bottom" => array("tag" => "integer"), + "page-label" => array("tag" => "textWithoutLanguage"), + "page-left" => array("tag" => "integer"), + "page-right" => array("tag" => "integer"), + "page-set" => array("tag" => "keyword"), + "page-top" => array("tag" => "integer"), + "penwidth" => array("tag" => "integer"), + "position" => array("tag" => "keyword"), + "ppi" => array("tag" => "integer"), + "prettyprint" => array("tag","boolean"), + "saturation" => array("tag" => "integer"), + "scaling" => array("tag" => "integer"), + "wrap" => array("tag","boolean"), + + ); + $this->job_tags = array_merge ($this->job_tags, $job_tags); + } + // }}} + +// +// REQUEST BUILDING +// + + // {{{ _enumBuild ($tag,$value) + protected function _enumBuild ($tag,$value) { + + $value_built = parent::_enumBuild($tag,$value); + + + switch ($tag) { + case "cpi": + switch ($value) { + case '10': + $value_built = chr(10); + break; + case '12': + $value_built = chr(12); + break; + case '17': + $value_built = chr(17); + break; + default: + $value_built = chr(10); + } + break; + case "lpi": + switch ($value) { + case '6': + $value_built = chr(6); + break; + case '8': + $value_built = chr(8); + break; + default: + $value_built = chr(6); + } + break; + } + + $prepend = ''; + while ((strlen($value_built) + strlen($prepend)) < 4) + $prepend .= chr(0); + return $prepend.$value_built; + } + // }}} + +// +// RESPONSE PARSING +// + + // {{{ _getAvailablePrinters () + private function _getAvailablePrinters () { + + $this->available_printers = array(); + $k = 0; + $this->printers_attributes = new stdClass(); + + for ($i = 0 ; (array_key_exists($i,$this->serveroutput->response)) ; $i ++) + if (($this->serveroutput->response[$i]['attributes']) == "printer-attributes") { + $phpname = "_printer".$k; + $this->printers_attributes->$phpname = new stdClass(); + for ($j = 0 ; array_key_exists($j,$this->serveroutput->response[$i]) ; $j++) { + + $value = $this->serveroutput->response[$i][$j]['value']; + $name = str_replace("-","_",$this->serveroutput->response[$i][$j]['name']); + + switch ($name) { + case "printer_uri_supported": + $this->available_printers = array_merge($this->available_printers,array($value)); + break; + case "printer_type": + $table = self::_interpretPrinterType($value); + $this->printers_attributes->$phpname->$name = new stdClass(); + + for($l = 0 ; $l < count($table) ; $l++ ) { + $index = '_value'.$l; + $this->printers_attributes->$phpname->$name->$index = $table[$l]; + } + + break; + case '': + break; + default: + $this->printers_attributes->$phpname->$name = $value; + break; + } + + } + $k ++; + } + } + // }}} + + // {{{ _getEnumVendorExtensions + protected function _getEnumVendorExtensions ($value_parsed) { + switch ($value_parsed) { + case 0x4002: + $value = 'Get-Availables-Printers'; + break; + default: + $value = sprintf('Unknown(Cups extension for operations): 0x%x',$value_parsed); + break; + } + + if (isset($value)) + return ($value); + + return sprintf('Unknown: 0x%x',$value_parsed); + } + // }}} + + // {{{ _interpretPrinterType($type) + private function _interpretPrinterType($value) { + $value_parsed = 0; + for ($i = strlen($value) ; $i > 0 ; $i --) + $value_parsed += pow(256,($i - 1)) * ord($value[strlen($value) - $i]); + + $type[0] = $type[1] = $type[2] = $type[3] = $type[4] = $type[5] = ''; + $type[6] = $type[7] = $type[8] = $type[9] = $type[10] = ''; + $type[11] = $type[12] = $type[13] = $type[14] = $type[15] = ''; + $type[16] = $type[17] = $type[18] = $type[19] = ''; + + if ($value_parsed %2 == 1) { + $type[0] = 'printer-class'; + $value_parsed -= 1; + } + if ($value_parsed %4 == 2 ) { + $type[1] = 'remote-destination'; + $value_parsed -= 2; + } + if ($value_parsed %8 == 4 ) { + $type[2] = 'print-black'; + $value_parsed -= 4; + } + if ($value_parsed %16 == 8 ) { + $type[3] = 'print-color'; + $value_parsed -= 8; + } + if ($value_parsed %32 == 16) { + $type[4] = 'hardware-print-on-both-sides'; + $value_parsed -= 16; + } + if ($value_parsed %64 == 32) { + $type[5] = 'hardware-staple-output'; + $value_parsed -= 32; + } + if ($value_parsed %128 == 64) { + $type[6] = 'hardware-fast-copies'; + $value_parsed -= 64; + } + if ($value_parsed %256 == 128) { + $type[7] = 'hardware-fast-copy-collation'; + $value_parsed -= 128; + } + if ($value_parsed %512 == 256) { + $type[8] = 'punch-output'; + $value_parsed -= 256; + } + if ($value_parsed %1024 == 512) { + $type[9] = 'cover-output'; + $value_parsed -= 512; + } + if ($value_parsed %2048 == 1024) { + $type[10] = 'bind-output'; + $value_parsed -= 1024; + } + if ($value_parsed %4096 == 2048) { + $type[11] = 'sort-output'; + $value_parsed -= 2048; + } + if ($value_parsed %8192 == 4096) { + $type[12] = 'handle-media-up-to-US-Legal-A4'; + $value_parsed -= 4096; + } + if ($value_parsed %16384 == 8192) { + $type[13] = 'handle-media-between-US-Legal-A4-and-ISO_C-A2'; + $value_parsed -= 8192; + } + if ($value_parsed %32768 == 16384) { + $type[14] = 'handle-media-larger-than-ISO_C-A2'; + $value_parsed -= 16384; + } + if ($value_parsed %65536 == 32768) { + $type[15] = 'handle-user-defined-media-sizes'; + $value_parsed -= 32768; + } + if ($value_parsed %131072 == 65536) { + $type[16] = 'implicit-server-generated-class'; + $value_parsed -= 65536; + } + if ($value_parsed %262144 == 131072) { + $type[17] = 'network-default-printer'; + $value_parsed -= 131072; + } + if ($value_parsed %524288 == 262144) { + $type[18] = 'fax-device'; + $value_parsed -= 262144; + } + return $type; + } + // }}} + + // {{{ _interpretEnum() + protected function _interpretEnum($attribute_name,$value) { + + $value_parsed = self::_interpretInteger($value); + + switch ($attribute_name) { + case 'cpi': + case 'lpi': + $value = $value_parsed; + break; + default: + $value = parent::_interpretEnum($attribute_name,$value); + break; + } + + + return $value; + } + // }}} + +}; + +/* + * Local variables: + * mode: php + * tab-width: 4 + * c-basic-offset: 4 + * End: + */ +?> diff --git a/Moodle/mod/print/ExtendedPrintIPP.php b/Moodle/mod/print/ExtendedPrintIPP.php new file mode 100755 index 0000000..e736f4b --- /dev/null +++ b/Moodle/mod/print/ExtendedPrintIPP.php @@ -0,0 +1,1441 @@ +document_uri = $uri; + $this->setup->uri = 1; + } + + if(!$this->_stringUri()) + return FALSE; + + $this->output = $this->stringjob; + + $post_values = array( "Content-Type" => "application/ipp", + "Data" => $this->output); + + + if (self::_sendHttp ($post_values,$this->paths['printers'])) { + + if(self::_parseServerOutput()) { + $this->_parseJobAttributes(); + $this->_getJobId(); + //$this->_getPrinterUri(); + $this->_getJobUri(); + } + } + + $this->attributes = &$this->job_attributes; + + if (isset($this->serveroutput) && isset($this->serveroutput->status)) { + + $this->status = array_merge($this->status,array($this->serveroutput->status)); + if ($this->serveroutput->status == "successfull-ok") + self::_errorLog(sprintf("printing uri %s, job %s: ",$uri,$this->last_job) + .$this->serveroutput->status,3); + else { + $this->jobs = array_merge($this->jobs,array("")); + $this->jobs_uri = array_merge($this->jobs_uri,array("")); + self::_errorLog(sprintf("printing uri %s: ",$uri,$this->last_job) + .$this->serveroutput->status,1); + } + return $this->serveroutput->status; + } + + $this->status = array_merge($this->status,array("OPERATION FAILED")); + self::_errorLog("printing uri $uri : OPERATION FAILED",1); + + return false; + } + // }}} + + // {{{ purgeJobs() + public function purgeJobs() { + + $this->jobs = array_merge($this->jobs,array("")); + $this->jobs_uri = array_merge($this->jobs_uri,array("")); + + self::_setOperationId(); + $this->parsed = array(); + unset($this->printer_attributes); + + if (!isset($this->setup->uri)) { + $this->getPrinters(); + unset($this->jobs[count($this->jobs) - 1]); + unset($this->jobs_uri[count($this->jobs_uri) - 1]); + unset($this->status[count($this->status) - 1]); + + if (array_key_exists(0,$this->available_printers)) + self::setPrinterURI($this->available_printers[0]); + else { + trigger_error(_("purgeJobs: Printer URI is not set: die"),E_USER_WARNING); + self::_putDebug( _("purgeJobs: Printer URI is not set: die\n")); + self::_errorLog("purgeJobs: Printer URI is not set, die",2); + return FALSE; + } + } + + if (!isset($this->setup->charset)) + self::setCharset('us-ascii'); + + if (!isset($this->setup->language)) + self::setLanguage('en_us'); + + if (!isset($this->meta->username)) + self::setUserName(); + + $this->stringjob = chr(0x01) . chr(0x01) // 1.1 | version-number + . chr(0x00) . chr (0x12) // purge-Jobs | operation-id + . $this->meta->operation_id // request-id + . chr(0x01) // start operation-attributes | operation-attributes-tag + . $this->meta->charset + . $this->meta->language + . $this->meta->printer_uri + . $this->meta->username + . chr(0x22) + . self::_giveMeStringLength("purge-jobs") + . "purge-jobs" + . self::_giveMeStringLength(chr(0x01)) + . chr(0x01) + . chr(0x03); // end-of-attributes | end-of-attributes-tag + + self::_putDebug(sprintf(_("String sent to the server is:\n%s\n"), $this->stringjob)); + + self::_putDebug(sprintf(_("purging jobs of %s\n"),$this->printer_uri)); + + $this->output = $this->stringjob; + + $post_values = array( "Content-Type"=>"application/ipp", + "Data"=>$this->output); + + if (self::_sendHttp ($post_values,$this->paths['admin'])) { + self::_parseServerOutput(); + self::_parseAttributes(); + } + + + if (isset($this->serveroutput) && isset($this->serveroutput->status)) { + + $this->status = array_merge($this->status,array($this->serveroutput->status)); + + if ($this->serveroutput->status == "successfull-ok") + self::_errorLog(sprintf(_("purging jobs of %s: "),$this->printer_uri) + .$this->serveroutput->status,3); + else + self::_errorLog(sprintf(_("purging jobs of %s: "),$this->printer_uri) + .$this->serveroutput->status,1); + + return $this->serveroutput->status; + } + + $this->status = array_merge($this->status,array("OPERATION FAILED")); + self::_errorLog(date("Y-m-d H:i:s : ") + .basename($_SERVER['PHP_SELF']) + .sprintf(_("purging jobs of %s : OPERATION FAILED"), + $this->printer_uri),3); + + return false; + } + + // }}} + + // {{{ createJob() + public function createJob() { + + + self::_setOperationId(); + $this->parsed = array(); + unset($this->printer_attributes); + + if (!isset($this->setup->uri)) { + $this->getPrinters(); + unset($this->jobs[count($this->jobs) - 1]); + unset($this->jobs_uri[count($this->jobs_uri) - 1]); + unset($this->status[count($this->status) - 1]); + + if (array_key_exists(0,$this->available_printers)) + self::setPrinterURI($this->available_printers[0]); + else { + trigger_error(_("createJob: Printer URI is not set: die"),E_USER_WARNING); + self::_putDebug( _("createJob: Printer URI is not set: die\n")); + self::_errorLog("createJob: Printer URI is not set, die",2); + return FALSE; + } + } + + if (!isset($this->setup->charset)) + self::setCharset('us-ascii'); + + if (!isset($this->setup->language)) + self::setLanguage('en_us'); + + if (!isset($this->meta->username)) + self::setUserName(); + + if (!isset($this->setup->copies)) + self::setCopies(1); + + if (!isset($this->meta->fidelity)) + $this->meta->fidelity = ''; + + if (!isset($this->meta->sides)) + $this->meta->sides = ''; + + if (!isset($this->meta->page_ranges)) + $this->meta->page_ranges = ''; + + if (!isset($this->setup->jobname)) + if (is_readable($this->data)) + self::setJobName(basename($this->data),true); + else + self::setJobName(); + unset($this->setup->jobname); + + if (!isset($this->timeout)) + $this->timeout = 60; + + $timeout = self::_integerBuild($this->timeout); + + + $this->meta->timeout = chr(0x21) // integer + . self::_giveMeStringLength("multiple-operation-time-out") + . "multiple-operation-time-out" + . self::_giveMeStringLength($timeout) + . $timeout; + + $jobattributes = ''; + $operationattributes = ''; + $printerattributes = ''; + self::_buildValues($operationattributes,$jobattributes,$printerattributes); + + $this->stringjob = chr(0x01) . chr(0x01) // 1.1 | version-number + . chr(0x00) . chr (0x05) // Create-Job | operation-id + . $this->meta->operation_id // request-id + . chr(0x01) // start operation-attributes | operation-attributes-tag + . $this->meta->charset + . $this->meta->language + . $this->meta->printer_uri + . $this->meta->username + . $this->meta->jobname + . $this->meta->fidelity + . $this->meta->timeout + . $operationattributes + . chr(0x02) // start job-attributes | job-attributes-tag + . $this->meta->copies + . $this->meta->sides + . $this->meta->page_ranges + . $jobattributes + . chr(0x03); // end-of-attributes | end-of-attributes-tag + + unset ($this->meta->copies,$this->meta->sides,$this->meta->page_ranges); + + self::_putDebug(sprintf(_("String sent to the server is:\n%s\n"), $this->stringjob)); + + self::_putDebug(sprintf(_("creating job %s, printer %s\n"),$this->last_job,$this->printer_uri)); + + $this->output = $this->stringjob; + + $post_values = array( "Content-Type"=>"application/ipp", + "Data"=>$this->output); + + if (self::_sendHttp ($post_values,$this->paths['printers'])) + if(self::_parseServerOutput()) { + $this->_getJobId(); + $this->_getJobUri(); + $this->_parseJobAttributes(); + } else { + $this->jobs = array_merge($this->jobs,array('')); + $this->jobs_uri = array_merge($this->jobs_uri,array('')); + } + + + + + + if (isset($this->serveroutput) && isset($this->serveroutput->status)) { + + $this->status = array_merge($this->status,array($this->serveroutput->status)); + + if ($this->serveroutput->status == "successfull-ok") + self::_errorLog(sprintf(_("Create job: job %s"),$this->last_job) + .$this->serveroutput->status,3); + else { + + $this->jobs = array_merge($this->jobs,array("")); + $this->jobs_uri = array_merge($this->jobs_uri,array("")); + self::_errorLog(sprintf(_("Create-Job: %s"),$this->serveroutput->status),1); + } + return $this->serveroutput->status; + } + + $this->status = array_merge($this->status,array("OPERATION FAILED")); + self::_errorLog(date("Y-m-d H:i:s : ") + .basename($_SERVER['PHP_SELF']) + .sprintf(_("Creating job on %s : OPERATION FAILED"), + $this->printer_uri),3); + + $this->jobs = array_merge($this->jobs,array("")); + $this->jobs_uri = array_merge($this->jobs_uri,array("")); + return false; + } + + // }}} + + // {{{ sendDocument($job) + public function sendDocument($job,$is_last=false){ + + self::_putDebug( sprintf("*************************\nDate: %s\n*************************\n\n",date('Y-m-d H:i:s'))); + + if (!$this->_stringDocument($job,$is_last)) + return FALSE; + + if (is_readable($this->data)){ + self::_putDebug( _("sending Document\n")); + + $this->output = $this->stringjob; + + if ($this->setup->datatype == "TEXT") + $this->output .= chr(0x16); // ASCII "SYN" + + + $post_values = array( "Content-Type" => "application/ipp", + "Data" => $this->output, + "File" => $this->data); + + if ($this->setup->datatype == "TEXT" && !isset($this->setup->noFormFeed)) + $post_values = array_merge($post_values,array("Filetype"=>"TEXT")); + + } else { + self::_putDebug( _("sending DATA as document\n")); + + $this->output = $this->stringjob; + $this->output .= $this->datahead; + $this->output .= $this->data; + $this->output .= $this->datatail; + + $post_values = array( "Content-Type" => "application/ipp", + "Data" => $this->output); + + + } + + if (self::_sendHttp ($post_values,$this->paths['printers'])) { + + if(self::_parseServerOutput()) { + $this->_getJobId(); + //$this->_getPrinterUri(); + $this->_getJobUri(); + $this->_parseJobAttributes(); + } else { + $this->jobs = array_merge($this->jobs,array($job)); + $this->jobs_uri = array_merge($this->jobs_uri,array($job)); + } + + } + + if (isset($this->serveroutput) && isset($this->serveroutput->status)) { + + $this->status = array_merge($this->status,array($this->serveroutput->status)); + + if ($this->serveroutput->status == "successfull-ok") + self::_errorLog(sprintf("sending document, job %s: %s",$job,$this->serveroutput->status),3); + else { + $this->jobs = array_merge($this->jobs,array("")); + $this->jobs_uri = array_merge($this->jobs_uri,array("")); + self::_errorLog(sprintf("sending document, job %s: %s",$job,$this->serveroutput->status),1); + } + return $this->serveroutput->status; + + } + + $this->status = array_merge($this->status,array("OPERATION FAILED")); + $this->jobs = array_merge($this->jobs,array($job)); + $this->jobs_uri = array_merge($this->jobs_uri,array($job)); + self::_errorLog(sprintf("sending document, job %s : OPERATION FAILED",$job),1); + + return false; + } + // }}} + + // {{{ sendURI ($uri,$job,$is_last=false) + public function sendURI ($uri,$job,$is_last=false){ + + self::_putDebug( sprintf("*************************\nDate: %s\n*************************\n\n",date('Y-m-d H:i:s'))); + + if (!$this->_stringSendUri($uri,$job,$is_last)) + return FALSE; + + self::_putDebug( _("sending URI $uri\n")); + + $this->output = $this->stringjob; + + $post_values = array( "Content-Type" => "application/ipp", + "Data" => $this->output); + + if (self::_sendHttp ($post_values,$this->paths['printers'])) { + + if(self::_parseServerOutput()) { + $this->_getJobId(); + //$this->_getPrinterUri(); + $this->_getJobUri(); + $this->_parseJobAttributes(); + } else { + $this->jobs = array_merge($this->jobs,array($job)); + $this->jobs_uri = array_merge($this->jobs_uri,array($job)); + } + + } + + $this->attributes = &$this->job_attributes; + + if (isset($this->serveroutput) && isset($this->serveroutput->status)) { + + $this->status = array_merge($this->status,array($this->serveroutput->status)); + + if ($this->serveroutput->status == "successfull-ok") + self::_errorLog(sprintf("sending uri %s, job %s: %s",$uri,$job,$this->serveroutput->status),3); + else { + $this->jobs = array_merge($this->jobs,array("")); + $this->jobs_uri = array_merge($this->jobs_uri,array("")); + self::_errorLog(sprintf("sending uri, job %s: %s",$uri,$job,$this->serveroutput->status),1); + } + return $this->serveroutput->status; + + } + + $this->status = array_merge($this->status,array("OPERATION FAILED")); + $this->jobs = array_merge($this->jobs,array($job)); + $this->jobs_uri = array_merge($this->jobs_uri,array($job)); + self::_errorLog(sprintf("sending uri %s, job %s : OPERATION FAILED",$uri,$job),1); + + return false; + } + // }}} + + // {{{ pausePrinter () + public function pausePrinter() { + + $this->jobs = array_merge($this->jobs,array("")); + $this->jobs_uri = array_merge($this->jobs_uri,array("")); + + self::_setOperationId(); + $this->parsed = array(); + unset($this->printer_attributes); + + if (!isset($this->setup->uri)) { + $this->getPrinters(); + unset($this->jobs[count($this->jobs) - 1]); + unset($this->jobs_uri[count($this->jobs_uri) - 1]); + unset($this->status[count($this->status) - 1]); + + if (array_key_exists(0,$this->available_printers)) + self::setPrinterURI($this->available_printers[0]); + else { + trigger_error(_("pausePrinter: Printer URI is not set: die"),E_USER_WARNING); + self::_putDebug( _("pausePrinter: Printer URI is not set: die\n")); + self::_errorLog("pausePrinter: Printer URI is not set, die",2); + return FALSE; + } + } + + if (!isset($this->setup->charset)) + self::setCharset('us-ascii'); + + if (!isset($this->setup->language)) + self::setLanguage('en_us'); + + if (!isset($this->meta->username)) + self::setUserName(); + + $this->stringjob = chr(0x01) . chr(0x01) // 1.1 | version-number + . chr(0x00) . chr (0x10) // Pause-Printer | operation-id + . $this->meta->operation_id // request-id + . chr(0x01) // start operation-attributes | operation-attributes-tag + . $this->meta->charset + . $this->meta->language + . $this->meta->printer_uri + . $this->meta->username + /* . chr(0x22) + . self::_giveMeStringLength("purge-jobs") + . "purge-jobs" + . self::_giveMeStringLength(chr(0x01)) + . chr(0x01) */ + . chr(0x03); // end-of-attributes | end-of-attributes-tag + + self::_putDebug(sprintf(_("String sent to the server is:\n%s\n"), $this->stringjob)); + + self::_putDebug(sprintf(_("pause printer %s\n"),$this->printer_uri)); + + $this->output = $this->stringjob; + + $post_values = array( "Content-Type"=>"application/ipp", + "Data"=>$this->output); + + if (self::_sendHttp ($post_values,$this->paths['admin'])) { + self::_parseServerOutput(); + self::_parseAttributes(); + } + + + if (isset($this->serveroutput) && isset($this->serveroutput->status)) { + + $this->status = array_merge($this->status,array($this->serveroutput->status)); + + if ($this->serveroutput->status == "successfull-ok") + self::_errorLog(sprintf(_("Pause printer %s: "),$this->printer_uri) + .$this->serveroutput->status,3); + else + self::_errorLog(sprintf(_("pause printer %s: "),$this->printer_uri) + .$this->serveroutput->status,1); + + return $this->serveroutput->status; + } + + $this->status = array_merge($this->status,array("OPERATION FAILED")); + self::_errorLog(date("Y-m-d H:i:s : ") + .basename($_SERVER['PHP_SELF']) + .sprintf(_("pause printer %s : OPERATION FAILED"), + $this->printer_uri),3); + + return false; + } + // }}} + + // {{{ resumePrinter () + public function resumePrinter() { + + $this->jobs = array_merge($this->jobs,array("")); + $this->jobs_uri = array_merge($this->jobs_uri,array("")); + + self::_setOperationId(); + $this->parsed = array(); + unset($this->printer_attributes); + + if (!isset($this->setup->uri)) { + $this->getPrinters(); + unset($this->jobs[count($this->jobs) - 1]); + unset($this->jobs_uri[count($this->jobs_uri) - 1]); + unset($this->status[count($this->status) - 1]); + + if (array_key_exists(0,$this->available_printers)) + self::setPrinterURI($this->available_printers[0]); + else { + trigger_error(_("resumePrinter: Printer URI is not set: die"),E_USER_WARNING); + self::_putDebug( _("resumePrinter: Printer URI is not set: die\n")); + self::_errorLog(" Printer URI is not set, die",2); + return FALSE; + } + } + + if (!isset($this->setup->charset)) + self::setCharset('us-ascii'); + + if (!isset($this->setup->language)) + self::setLanguage('en_us'); + + if (!isset($this->meta->username)) + self::setUserName(); + + $this->stringjob = chr(0x01) . chr(0x01) // 1.1 | version-number + . chr(0x00) . chr (0x11) // suse-Printer | operation-id + . $this->meta->operation_id // request-id + . chr(0x01) // start operation-attributes | operation-attributes-tag + . $this->meta->charset + . $this->meta->language + . $this->meta->printer_uri + . $this->meta->username + . chr(0x03); // end-of-attributes | end-of-attributes-tag + + self::_putDebug(sprintf(_("String sent to the server is:\n%s\n"), $this->stringjob)); + + self::_putDebug(sprintf(_("resume printer %s\n"),$this->printer_uri)); + + $this->output = $this->stringjob; + + $post_values = array( "Content-Type"=>"application/ipp", + "Data"=>$this->output); + + if (self::_sendHttp ($post_values,$this->paths['admin'])) { + self::_parseServerOutput(); + self::_parseAttributes(); + } + + + if (isset($this->serveroutput) && isset($this->serveroutput->status)) { + + $this->status = array_merge($this->status,array($this->serveroutput->status)); + + if ($this->serveroutput->status == "successfull-ok") + self::_errorLog(sprintf(_("resume printer %s: "),$this->printer_uri) + .$this->serveroutput->status,3); + else + self::_errorLog(sprintf(_("resume printer %s: "),$this->printer_uri) + .$this->serveroutput->status,1); + + return $this->serveroutput->status; + } + + $this->status = array_merge($this->status,array("OPERATION FAILED")); + self::_errorLog(date("Y-m-d H:i:s : ") + .basename($_SERVER['PHP_SELF']) + .sprintf(_("resume printer %s : OPERATION FAILED"), + $this->printer_uri),3); + + return false; + } + // }}} + + // {{{ holdJob ($job_uri) + public function holdJob ($job_uri,$until='indefinite') { + + $this->jobs = array_merge($this->jobs,array("")); + $this->jobs_uri = array_merge($this->jobs_uri,array(trim($job_uri))); + + self::_setOperationId(); + $this->parsed = array(); + unset($this->printer_attributes); + + if (!isset($this->setup->charset)) + self::setCharset('us-ascii'); + + if (!isset($this->setup->language)) + self::setLanguage('en_us'); + + if (!isset($this->meta->username)) + self::setUserName(); + + if (!isset($this->meta->message)) + $this->meta->message = ''; + + self::_setJobUri($job_uri); + + $until_strings = array('no-hold','day-time','evening','night','weekend','second-shift','third-shift'); + if (in_array($until,$until_strings)) + true; + else + $until = 'indefinite'; + + $this->meta->job_hold_until = chr(0x42) // keyword + . self::_giveMeStringLength('job-hold-until') + . 'job-hold-until' + . self::_giveMeStringLength($until) + . $until; + + $this->stringjob = chr(0x01) . chr(0x01) // 1.1 | version-number + . chr(0x00) . chr (0x0C) // Hold-Job | operation-id + . $this->meta->operation_id // request-id + . chr(0x01) // start operation-attributes | operation-attributes-tag + . $this->meta->charset + . $this->meta->language + . $this->meta->username + . $this->meta->job_uri + . $this->meta->message + . $this->meta->job_hold_until + . chr(0x03); // end-of-attributes | end-of-attributes-tag + + self::_putDebug(sprintf(_("String sent to the server is:\n%s\n"), $this->stringjob)); + + self::_putDebug(sprintf(_("hold job %s until %s\n"),$job_uri,$until)); + + $this->output = $this->stringjob; + + $post_values = array( "Content-Type"=>"application/ipp", + "Data"=>$this->output); + + if (self::_sendHttp ($post_values,$this->paths['jobs'])) { + self::_parseServerOutput(); + self::_parseAttributes(); + } + if (isset($this->serveroutput) && isset($this->serveroutput->status)) { + + $this->status = array_merge($this->status,array($this->serveroutput->status)); + + if ($this->serveroutput->status == "successfull-ok") + self::_errorLog(sprintf(_("hold job %s until %s: "),$job_uri,$until) + .$this->serveroutput->status,3); + else + self::_errorLog(sprintf(_("hold job %s until %s: "),$job_uri,$until) + .$this->serveroutput->status,1); + + return $this->serveroutput->status; + } + + $this->status = array_merge($this->status,array("OPERATION FAILED")); + self::_errorLog(date("Y-m-d H:i:s : ") + .basename($_SERVER['PHP_SELF']) + .sprintf(_("hold job %s until %s : OPERATION FAILED"), + $job_uri,$until),3); + + return false; + } + // }}} + + // {{{ releaseJob ($job_uri) + public function releaseJob ($job_uri) { + + $this->jobs = array_merge($this->jobs,array("")); + $this->jobs_uri = array_merge($this->jobs_uri,array(trim($job_uri))); + + self::_setOperationId(); + $this->parsed = array(); + unset($this->printer_attributes); + + if (!isset($this->setup->charset)) + self::setCharset('us-ascii'); + + if (!isset($this->setup->language)) + self::setLanguage('en_us'); + + if (!isset($this->meta->username)) + self::setUserName(); + + if (!isset($this->meta->message)) + $this->meta->message = ''; + + self::_setJobUri($job_uri); + + $this->stringjob = chr(0x01) . chr(0x01) // 1.1 | version-number + . chr(0x00) . chr (0x0D) // Hold-Job | operation-id + . $this->meta->operation_id // request-id + . chr(0x01) // start operation-attributes | operation-attributes-tag + . $this->meta->charset + . $this->meta->language + . $this->meta->job_uri + . $this->meta->username + . $this->meta->message + . chr(0x03); // end-of-attributes | end-of-attributes-tag + + self::_putDebug(sprintf(_("String sent to the server is:\n%s\n"), $this->stringjob)); + + self::_putDebug(sprintf(_("release job %s\n"),$job_uri)); + + $this->output = $this->stringjob; + + $post_values = array( "Content-Type"=>"application/ipp", + "Data"=>$this->output); + + if (self::_sendHttp ($post_values,$this->paths['jobs'])) { + self::_parseServerOutput(); + self::_parseAttributes(); + } + if (isset($this->serveroutput) && isset($this->serveroutput->status)) { + + $this->status = array_merge($this->status,array($this->serveroutput->status)); + + if ($this->serveroutput->status == "successfull-ok") + self::_errorLog(sprintf(_("release job %s: "),$job_uri) + .$this->serveroutput->status,3); + else + self::_errorLog(sprintf(_("release job %s: "),$job_uri) + .$this->serveroutput->status,1); + + return $this->serveroutput->status; + } + + $this->status = array_merge($this->status,array("OPERATION FAILED")); + self::_errorLog(date("Y-m-d H:i:s : ") + .basename($_SERVER['PHP_SELF']) + .sprintf(_("release job %s: OPERATION FAILED"), + $job_uri),3); + + return false; + } + // }}} + + // {{{ restartJob ($job_uri) + public function restartJob ($job_uri) { + + $this->jobs = array_merge($this->jobs,array("")); + $this->jobs_uri = array_merge($this->jobs_uri,array(trim($job_uri))); + + self::_setOperationId(); + $this->parsed = array(); + unset($this->printer_attributes); + + if (!isset($this->setup->charset)) + self::setCharset('us-ascii'); + + if (!isset($this->setup->language)) + self::setLanguage('en_us'); + + if (!isset($this->meta->username)) + self::setUserName(); + + if (!isset($this->meta->message)) + $this->meta->message = ''; + + self::_setJobUri($job_uri); + + + $jobattributes = ''; + $operationattributes = ''; + $printerattributes = ''; + self::_buildValues ($operationattributes,$jobattributes,$printerattributes); + + + $this->stringjob = chr(0x01) . chr(0x01) // 1.1 | version-number + . chr(0x00) . chr (0x0E) // Hold-Job | operation-id + . $this->meta->operation_id // request-id + . chr(0x01) // start operation-attributes | operation-attributes-tag + . $this->meta->charset + . $this->meta->language + . $this->meta->job_uri + . $this->meta->username + . $this->meta->message + . $jobattributes // job-hold-until is set by setAttribute($attribute,$value) + . chr(0x03); // end-of-attributes | end-of-attributes-tag + + self::_putDebug(sprintf(_("String sent to the server is:\n%s\n"), $this->stringjob)); + + self::_putDebug(sprintf(_("release job %s\n"),$job_uri)); + + $this->output = $this->stringjob; + + $post_values = array( "Content-Type"=>"application/ipp", + "Data"=>$this->output); + + if (self::_sendHttp ($post_values,$this->paths['jobs'])) { + self::_parseServerOutput(); + self::_parseAttributes(); + } + + if (isset($this->serveroutput) && isset($this->serveroutput->status)) { + + $this->status = array_merge($this->status,array($this->serveroutput->status)); + + if ($this->serveroutput->status == "successfull-ok") + self::_errorLog(sprintf(_("release job %s: "),$job_uri) + .$this->serveroutput->status,3); + else + self::_errorLog(sprintf(_("release job %s: "),$job_uri) + .$this->serveroutput->status,1); + + return $this->serveroutput->status; + } + + $this->status = array_merge($this->status,array("OPERATION FAILED")); + self::_errorLog(date("Y-m-d H:i:s : ") + .basename($_SERVER['PHP_SELF']) + .sprintf(_("release job %s: OPERATION FAILED"), + $job_uri),3); + + return false; + } + // }}} + + // {{{ setJobAttributes ($job_uri,$deleted_attributes=array()) + public function setJobAttributes ($job_uri,$deleted_attributes=array()) { + + $this->jobs = array_merge($this->jobs,array("")); + $this->jobs_uri = array_merge($this->jobs_uri,array(trim($job_uri))); + + self::_setOperationId(); + $this->parsed = array(); + unset ($this->attributes); + + if (!isset($this->setup->charset)) + self::setCharset('us-ascii'); + + if (!isset($this->setup->language)) + self::setLanguage('en_us'); + + if (!isset($this->meta->username)) + self::setUserName(); + + if (!isset($this->meta->message)) + $this->meta->message = ''; + + + if (!isset($this->meta->copies)) + $this->meta->copies = ''; + + if (!isset($this->meta->sides)) + $this->meta->sides = ''; + + if (!isset($this->meta->page_ranges)) + $this->meta->page_ranges = ''; + + self::_setJobUri($job_uri); + + $operationattributes = ''; + $jobattributes = ''; + $printerattributes = ''; + self::_buildValues ($operationattributes,$jobattributes,$printerattributes); + + $this->meta->deleted_attributes = ""; + for ($i = 0 ; $i < count($deleted_attributes) ; $i++) + $this->meta->deleted_attributes .= chr(0x16) // out-of-band value + . self::_giveMeStringLength($deleted_attributes[$i]) + . $deleted_attributes[$i] + . chr(0x0).chr(0x0); // value-length = 0; + + + $this->stringjob = chr(0x01) . chr(0x01) // 1.1 | version-number + . chr(0x00) . chr (0x14) // Set-Job-Attributes | operation-id + . $this->meta->operation_id // request-id + . chr(0x01) // start operation-attributes | operation-attributes-tag + . $this->meta->charset + . $this->meta->language + . $this->meta->job_uri + . $this->meta->username + . $this->meta->message + . chr(0x02) // start job-attributes + . $jobattributes // setteds by setAttribute($attribute,$value) + . $this->meta->copies + . $this->meta->sides + . $this->meta->page_ranges + . $this->meta->deleted_attributes + . chr(0x03); // end-of-attributes | end-of-attributes-tag + + self::_putDebug(sprintf(_("String sent to the server is:\n%s\n"), $this->stringjob)); + + self::_putDebug(sprintf(_("set job attributes for job %s\n"),$job_uri)); + + $this->output = $this->stringjob; + + $post_values = array( "Content-Type"=>"application/ipp", + "Data"=>$this->output); + + if (self::_sendHttp ($post_values,$this->paths['jobs'])) { + self::_parseServerOutput(); + self::_parseAttributes(); + } + if (isset($this->serveroutput) && isset($this->serveroutput->status)) { + + $this->status = array_merge($this->status,array($this->serveroutput->status)); + + if ($this->serveroutput->status == "successfull-ok") + self::_errorLog(sprintf(_("set job attributes for job %s: "),$job_uri) + .$this->serveroutput->status,3); + else + self::_errorLog(sprintf(_("set job attributes for job %s: "),$job_uri) + .$this->serveroutput->status,1); + $this->last_job = $job_uri; + $this->jobs_uri[count($this->jobs_uri) - 1] = $job_uri; + return $this->serveroutput->status; + } + + $this->status = array_merge($this->status,array("OPERATION FAILED")); + self::_errorLog(date("Y-m-d H:i:s : ") + .basename($_SERVER['PHP_SELF']) + .sprintf(_("set job attributes for job %s: OPERATION FAILED"), + $job_uri),3); + + return false; + } + // }}} + + // {{{ setPrinterAttributes () + public function setPrinterAttributes ($document_format='',$deleted_attributes=array()) { + /* $document_format (RFC 3380) + If the client includes this attribute, the Printer MUST change + the supplied attributes for the document format specified by + this attribute. If a supplied attribute is a member of the + "document-format-varying-attributes" (i.e., the attribute + varies by document format, see section 6.3), the Printer MUST + change the supplied attribute for the document format specified + by this attribute, but not for other document formats. If a + supplied attribute isn't a member of the "document-format- + varying-attributes" (i.e., it doesn't vary by document format), + the Printer MUST change the supplied attribute for all document + formats. + + If the client omits this attribute, the Printer MUST change the + supplied attributes for all document formats, whether or not + they vary by document-format. + */ + + $this->jobs = array_merge($this->jobs,array("")); + $this->jobs_uri = array_merge($this->jobs_uri,array("")); + unset ($this->attributes); + + self::_setOperationId(); + $this->parsed = array(); + + if (!isset($this->setup->charset)) + self::setCharset('us-ascii'); + + if (!isset($this->setup->language)) + self::setLanguage('en_us'); + + if (!isset($this->meta->username)) + self::setUserName(); + + if (!isset($this->meta->message)) + $this->meta->message = ''; + + if (!isset($this->meta->copies)) + $this->meta->copies = ''; + + if (!isset($this->meta->sides)) + $this->meta->sides = ''; + + if (!isset($this->meta->page_ranges)) + $this->meta->page_ranges = ''; + + if ($document_format) + $document_format = chr(0x49) // document-format tag + . self::_giveMeStringLength('document-format') + . 'document-format' // + . self::_giveMeStringLength($document_format) + . $document_format; // value + + $operationattributes = ''; + $jobattributes = ''; + $printerattributes = ''; + self::_buildValues ($operationattributes,$jobattributes,$printerattributes); + + $this->meta->deleted_attributes = ""; + for ($i = 0 ; $i < count($deleted_attributes) ; $i++) + $this->meta->deleted_attributes .= chr(0x16) // out-of-band "deleted" value + . self::_giveMeStringLength($deleted_attributes[$i]) + . $deleted_attributes[$i] + . chr(0x0).chr(0x0); // value-length = 0; + + + $this->stringjob = chr(0x01) . chr(0x01) // 1.1 | version-number + . chr(0x00) . chr (0x13) // Set-Printer-Attributes | operation-id + . $this->meta->operation_id // request-id + . chr(0x01) // start operation-attributes | operation-attributes-tag + . $this->meta->charset + . $this->meta->language + . $this->meta->printer_uri + . $this->meta->username + . $this->meta->message + . $operationattributes + . chr(0x02) // start job-attributes + . $jobattributes // setteds by setAttribute($attribute,$value) + . $this->meta->copies + . $this->meta->sides + . $this->meta->page_ranges + . $this->meta->deleted_attributes + . chr(0x03); // end-of-attributes | end-of-attributes-tag + + self::_putDebug(sprintf(_("String sent to the server is:\n%s\n"), $this->stringjob)); + + self::_putDebug(sprintf(_("set printer attributes for job %s\n"),$this->printer_uri)); + + $this->output = $this->stringjob; + + $post_values = array( "Content-Type"=>"application/ipp", + "Data"=>$this->output); + + if (self::_sendHttp ($post_values,$this->paths['printers'])) { + self::_parseServerOutput(); + self::_parseAttributes(); + } + if (isset($this->serveroutput) && isset($this->serveroutput->status)) { + + $this->status = array_merge($this->status,array($this->serveroutput->status)); + + if ($this->serveroutput->status == "successfull-ok") + self::_errorLog(sprintf(_("set printer attributes for printer %s: "),$this->printer_uri) + .$this->serveroutput->status,3); + else + self::_errorLog(sprintf(_("set printer attributes for printer %s: "),$this->printer_uri) + .$this->serveroutput->status,1); + + return $this->serveroutput->status; + } + + $this->status = array_merge($this->status,array("OPERATION FAILED")); + self::_errorLog(date("Y-m-d H:i:s : ") + .basename($_SERVER['PHP_SELF']) + .sprintf(_("set printer attributes for printer %s: OPERATION FAILED"), + $this->printer_uri),1); + + return false; + + } + // }}} + +// REQUEST BUILDING + + // {{{ _setDocumentUri ($job_uri) + protected function _setDocumentUri () { + + $this->meta->document_uri = chr(0x45) // type uri + . chr(0x00).chr(0x0c) // name-length + . "document-uri" + . self::_giveMeStringLength($this->document_uri) + . $this->document_uri; + + self::_putDebug( "document uri is: ".$this->document_uri."\n"); + $this->setup->document_uri = 1; + + } + // }}} + + // {{{ _stringUri () + protected function _stringUri () { + + self::_setDocumentUri(); + + if (!isset($this->setup->document_uri)) { + trigger_error(_("_stringUri: Document URI is not set: die"),E_USER_WARNING); + self::_putDebug( _("_stringUri: Document URI is not set: die\n")); + self::_errorLog("Document URI is not set, die",2); + return FALSE; + } + unset ($this->setup->document_uri); + + if (!isset($this->setup->uri)) { + $this->getPrinters(); + unset($this->jobs[count($this->jobs) - 1]); + unset($this->jobs_uri[count($this->jobs) - 1]); + unset($this->status[count($this->status) - 1]); + + if (array_key_exists(0,$this->available_printers)) + self::setPrinterURI($this->available_printers[0]); + else { + trigger_error(_("_stringUri: Printer URI is not set: die"),E_USER_WARNING); + self::_putDebug( _("_stringUri: Printer URI is not set: die\n")); + self::_errorLog("_stringUri: Printer URI is not set, die",2); + return FALSE; + } + } + + if (!isset($this->setup->charset)) + $this->meta->charset = ""; + // self::setCharset('us-ascii'); + if (!isset($this->setup->datatype)) + self::setBinary(); + if (!isset($this->setup->uri)) { + trigger_error(_("_stringUri: Printer URI is not set: die"),E_USER_WARNING); + self::_putDebug( _("_stringUri: Printer URI is not set: die\n")); + self::_errorLog("Printer URI is not set, die",2); + return FALSE; + } + if (!isset($this->setup->copies)) + self::setCopies(1); + + if (!isset($this->setup->language)) + self::setLanguage('en_us'); + + if (!isset($this->setup->mime_media_type)) + self::setMimeMediaType(); + unset ($this->setup->mime_media_type); + + if (!isset($this->setup->jobname)) + if (is_readable($this->data)) + self::setJobName(basename($this->data),true); + else + self::setJobName(); + unset($this->setup->jobname); + + if (!isset($this->meta->username)) + self::setUserName(); + + if (!isset($this->meta->fidelity)) + $this->meta->fidelity = ''; + + if (!isset($this->meta->document_name)) + $this->meta->document_name = ''; + + if (!isset($this->meta->sides)) + $this->meta->sides = ''; + + if (!isset($this->meta->page_ranges)) + $this->meta->page_ranges = ''; + + $jobattributes = ''; + $operationattributes = ''; + $printerattributes = ''; + self::_buildValues($operationattributes,$jobattributes,$printerattributes); + + self::_setOperationId(); + + if (!isset($this->error_generation->request_body_malformed)) + $this->error_generation->request_body_malformed = ""; + + $this->stringjob = chr(0x01) . chr(0x01) // 1.1 | version-number + . chr(0x00) . chr (0x03) // Print-URI | operation-id + . $this->meta->operation_id // request-id + . $this->error_generation->request_body_malformed + . chr(0x01) // start operation-attributes | operation-attributes-tag + . $this->meta->charset + . $this->meta->language + . $this->meta->printer_uri + . $this->meta->jobname + . $this->meta->username + . $this->meta->fidelity + . $this->meta->document_name + . $this->meta->document_uri + . $operationattributes + . chr(0x02) // start job-attributes | job-attributes-tag + . $this->meta->copies + . $this->meta->sides + . $this->meta->page_ranges + . $jobattributes + . chr(0x03); // end-of-attributes | end-of-attributes-tag + + self::_putDebug( sprintf(_("String sent to the server is:\n%s\n"), $this->stringjob)); + return TRUE; + } + // }}} + + // {{{ _stringDocument ($job,$is_last) + protected function _stringDocument ($job,$is_last) { + + if ($is_last == false) + $is_last = chr(0x00); + else + $is_last = chr(0x01); + + if (!isset($this->setup->charset)) + self::setCharset('us-ascii'); + if (!isset($this->setup->datatype)) + self::setBinary(); + + if (!isset($this->setup->uri)) { + $this->getPrinters(); + unset($this->jobs[count($this->jobs) - 1]); + unset($this->jobs_uri[count($this->jobs_uri) - 1]); + unset($this->status[count($this->status) - 1]); + + if (array_key_exists(0,$this->available_printers)) + self::setPrinterURI($this->available_printers[0]); + else { + trigger_error(_("_stringJob: Printer URI is not set: die"),E_USER_WARNING); + self::_putDebug( _("_stringJob: Printer URI is not set: die\n")); + self::_errorLog(" Printer URI is not set, die",2); + return FALSE; + } + } + + if (!isset($this->setup->copies)) + $this->meta->copies = ""; + + if (!isset($this->setup->language)) + self::setLanguage('en_us'); + + if (!isset($this->setup->mime_media_type)) + $this->meta->mime_media_type = ""; + if ($this->setup->datatype != "TEXT") + unset ($this->setup->mime_media_type); + + if (!isset($this->meta->fidelity)) + $this->meta->fidelity = ''; + + if (!isset($this->meta->document_name)) + $this->meta->document_name = ''; + + if (!isset($this->meta->sides)) + $this->meta->sides = ''; + + if (!isset($this->meta->page_ranges)) + $this->meta->page_ranges = ''; + + $operationattributes = ''; + $jobattributes = ''; + $printerattributes = ''; + self::_buildValues($operationattributes,$jobattributes,$printerattributes); + + self::_setOperationId(); + + + $this->stringjob = chr(0x01) . chr(0x01) // 1.1 | version-number + . chr(0x00) . chr (0x06) // Send-Document | operation-id + . $this->meta->operation_id // request-id + . chr(0x01) // start operation-attributes | operation-attributes-tag + . $this->meta->charset + . $this->meta->language + . chr(0x45) // attribute-type: uri + . self::_giveMeStringLength("job-uri") + . "job-uri" + . self::_giveMeStringLength($job) + . $job + . $this->meta->username + . $this->meta->document_name + . $this->meta->fidelity + . $this->meta->mime_media_type + . $operationattributes + . chr(0x22) // boolean + . self::_giveMeStringLength("last-document") + . "last-document" + . self::_giveMeStringLength($is_last) + . $is_last + . chr(0x03); // end-of-attributes | end-of-attributes-tag + + + self::_putDebug( sprintf(_("String sent to the server is:\n%s\n"), $this->stringjob)); + return TRUE; + } + // }}} + + // {{{ _stringSendUri ($uri,$job,$is_last) + protected function _stringSendUri ($uri,$job,$is_last) { + + $this->document_uri = $uri; + self::_setDocumentUri(); + + if (!isset($this->setup->document_uri)) { + trigger_error(_("_stringUri: Document URI is not set: die"),E_USER_WARNING); + self::_putDebug( _("_stringUri: Document URI is not set: die\n")); + self::_errorLog("Document URI is not set, die",2); + return FALSE; + } + unset ($this->setup->document_uri); + + + if ($is_last == false) + $is_last = chr(0x00); + else + $is_last = chr(0x01); + + if (!isset($this->setup->charset)) + self::setCharset('us-ascii'); + if (!isset($this->setup->datatype)) + self::setBinary(); + + if (!isset($this->setup->uri)) { + $this->getPrinters(); + unset($this->jobs[count($this->jobs) - 1]); + unset($this->jobs_uri[count($this->jobs_uri) - 1]); + unset($this->status[count($this->status) - 1]); + + if (array_key_exists(0,$this->available_printers)) + self::setPrinterURI($this->available_printers[0]); + else { + trigger_error(_("_stringJob: Printer URI is not set: die"),E_USER_WARNING); + self::_putDebug( _("_stringJob: Printer URI is not set: die\n")); + self::_errorLog(" Printer URI is not set, die",2); + return FALSE; + } + } + + if (!isset($this->setup->copies)) + $this->meta->copies = ""; + + if (!isset($this->setup->language)) + self::setLanguage('en_us'); + + if (!isset($this->setup->mime_media_type)) + $this->meta->mime_media_type = ""; + unset ($this->setup->mime_media_type); + + if (!isset($this->meta->fidelity)) + $this->meta->fidelity = ''; + + if (!isset($this->meta->document_name)) + $this->meta->document_name = ''; + + if (!isset($this->meta->sides)) + $this->meta->sides = ''; + + if (!isset($this->meta->page_ranges)) + $this->meta->page_ranges = ''; + + $operationattributes = ''; + $jobattributes = ''; + $printerattributes = ''; + self::_buildValues($operationattributes,$jobattributes,$printerattributes); + + self::_setOperationId(); + + + $this->stringjob = chr(0x01) . chr(0x01) // 1.1 | version-number + . chr(0x00) . chr (0x07) // Send-Uri | operation-id + . $this->meta->operation_id // request-id + . chr(0x01) // start operation-attributes | operation-attributes-tag + . $this->meta->charset + . $this->meta->language + . chr(0x45) // attribute-type: uri + . self::_giveMeStringLength("job-uri") + . "job-uri" + . self::_giveMeStringLength($job) + . $job + . $this->meta->username + . $this->meta->document_uri + . $this->meta->fidelity + . $this->meta->mime_media_type + . $operationattributes + . chr(0x22) // boolean + . self::_giveMeStringLength("last-document") + . "last-document" + . self::_giveMeStringLength($is_last) + . $is_last + . chr(0x03); // end-of-attributes | end-of-attributes-tag + + + self::_putDebug( sprintf(_("String sent to the server is:\n%s\n"), $this->stringjob)); + return TRUE; + } + // }}} + +}; + +/* + * Local variables: + * mode: php + * tab-width: 4 + * c-basic-offset: 4 + * End: + */ +?> diff --git a/Moodle/mod/print/PrintIPP.php b/Moodle/mod/print/PrintIPP.php new file mode 100755 index 0000000..7a2ce93 --- /dev/null +++ b/Moodle/mod/print/PrintIPP.php @@ -0,0 +1,1875 @@ +_stringJob()) + return FALSE; + + if (is_readable($this->data)){ + self::_putDebug( _("Printing a FILE\n"),3); + + $this->output = $this->stringjob; + + if ($this->setup->datatype == "TEXT") + $this->output .= chr(0x16); + + + $post_values = array( "Content-Type" => "application/ipp", + "Data" => $this->output, + "File" => $this->data); + + if ($this->setup->datatype == "TEXT" && !isset($this->setup->noFormFeed)) + $post_values = array_merge($post_values,array("Filetype"=>"TEXT")); + + } else { + self::_putDebug( _("Printing DATA\n"),3); + + $this->output = $this->stringjob; + $this->output .= $this->datahead; + $this->output .= $this->data; + $this->output .= $this->datatail; + + $post_values = array( "Content-Type" => "application/ipp", + "Data" => $this->output); + + + } + + if (self::_sendHttp ($post_values,$this->paths['printers'])) { + + if(self::_parseServerOutput()) { + $this->_getJobId(); + $this->_getJobUri(); + $this->_parseJobAttributes(); + } else { + $this->jobs = array_merge($this->jobs,array('')); + $this->jobs_uri = array_merge($this->jobs_uri,array('')); + } + + } + + if (isset($this->serveroutput) && isset($this->serveroutput->status)) { + + $this->status = array_merge($this->status,array($this->serveroutput->status)); + + if ($this->serveroutput->status == "successfull-ok") + { + self::_errorLog(sprintf("printing job %s: ",$this->last_job) .$this->serveroutput->status,3); + } + else + { + $this->jobs = array_merge($this->jobs,array("")); + $this->jobs_uri = array_merge($this->jobs_uri,array("")); + self::_errorLog(sprintf("printing job: ",$this->last_job) .$this->serveroutput->status,1); + if ($this->with_exceptions) + { + throw new ippException(sprintf("job status: %s", + $this->serveroutput->status)); + } + } + return $this->serveroutput->status; + + } + + $this->status = array_merge($this->status,array("OPERATION FAILED")); + $this->jobs = array_merge($this->jobs,array("")); + $this->jobs_uri = array_merge($this->jobs_uri,array("")); + self::_errorLog("printing job : OPERATION FAILED",1); + + return false; + } + // }}} + + // {{{ cancelJob ($job_uri) + public function cancelJob ($job_uri) { + + $this->jobs = array_merge($this->jobs,array("")); + $this->jobs_uri = array_merge($this->jobs_uri,array("")); + + self::_putDebug( sprintf("*************************\nDate: %s\n*************************\n\n",date('Y-m-d H:i:s'))); + + if (!$this->_stringCancel($job_uri)) + return FALSE; + + self::_putDebug( _("Cancelling Job $job_uri\n"),3); + + $this->output = $this->stringjob; + + $post_values = array( "Content-Type"=>"application/ipp", + "Data"=>$this->output); + + if (self::_sendHttp ($post_values,$this->paths['jobs'])) + self::_parseServerOutput(); + + + if (isset($this->serveroutput) && isset($this->serveroutput->status)) { + + $this->status = array_merge($this->status,array($this->serveroutput->status)); + + if ($this->serveroutput->status == "successfull-ok") + self::_errorLog("cancelling job $job_uri: ".$this->serveroutput->status,3); + else + self::_errorLog("cancelling job $job_uri: ".$this->serveroutput->status,1); + return $this->serveroutput->status; + + } + + $this->status = array_merge($this->status,array("OPERATION FAILED")); + self::_errorLog("cancelling job : OPERATION FAILED",3); + + return false; + } + // }}} + + // {{{ validateJob () + public function validateJob () { + + $this->jobs = array_merge($this->jobs,array("")); + $this->jobs_uri = array_merge($this->jobs_uri,array("")); + + $this->serveroutput->response = ''; + + self::_putDebug( sprintf("*************************\nDate: %s\n*************************\n\n",date('Y-m-d H:i:s'))); + + + self::_putDebug( _("Validate Job\n"),2); + + if (!isset($this->setup->charset)) + self::setCharset('us-ascii'); + if (!isset($this->setup->datatype)) + self::setBinary(); + + if (!isset($this->setup->uri)) { + $this->getPrinters(); + unset($this->jobs[count($this->jobs) - 1]); + unset($this->jobs_uri[count($this->jobs_uri) - 1]); + unset($this->status[count($this->status) - 1]); + + if (array_key_exists(0,$this->available_printers)) + self::setPrinterURI($this->available_printers[0]); + else { + trigger_error(_("_stringJob: Printer URI is not set: die"),E_USER_WARNING); + self::_putDebug( _("_stringJob: Printer URI is not set: die\n"),3); + self::_errorLog(" Printer URI is not set, die",2); + return FALSE; + } + } + + if (!isset($this->meta->copies)) + self::setCopies(1); + if (!isset($this->setup->copies)) + self::setCopies(1); + + if (!isset($this->setup->language)) + self::setLanguage('en_us'); + + if (!isset($this->setup->mime_media_type)) + self::setMimeMediaType(); + if ($this->setup->datatype != "TEXT") + unset ($this->setup->mime_media_type); + + if (!isset($this->setup->jobname)) + if (is_readable($this->data)) + self::setJobName(basename($this->data),true); + else + self::setJobName(); + unset($this->setup->jobname); + + if (!isset($this->meta->username)) + self::setUserName(); + + if (!isset($this->meta->fidelity)) + $this->meta->fidelity = ''; + + if (!isset($this->meta->document_name)) + $this->meta->document_name = ''; + + if (!isset($this->meta->sides)) + $this->meta->sides = ''; + + if (!isset($this->meta->page_ranges)) + $this->meta->page_ranges = ''; + + $jobattributes = ''; + $operationattributes = ''; + $printerattributes = ''; + self::_buildValues ($operationattributes,$jobattributes,$printerattributes); + + self::_setOperationId(); + + $this->stringjob = chr(0x01) . chr(0x01) // 1.1 | version-number + . chr(0x00) . chr (0x04) // Validate-Job | operation-id + . $this->meta->operation_id // request-id + . chr(0x01) // start operation-attributes | operation-attributes-tag + . $this->meta->charset + . $this->meta->language + . $this->meta->printer_uri + . $this->meta->username + . $this->meta->jobname + . $this->meta->fidelity + . $this->meta->document_name + . $this->meta->mime_media_type + . $operationattributes + . chr(0x02) // start job-attributes | job-attributes-tag + . $this->meta->copies + . $this->meta->sides + . $this->meta->page_ranges + . $jobattributes + . chr(0x03); // end-of-attributes | end-of-attributes-tag + + + self::_putDebug( sprintf(_("String sent to the server is:\n%s\n"), $this->stringjob)); + + $this->output = $this->stringjob; + + $post_values = array( "Content-Type"=>"application/ipp", + "Data"=>$this->output); + + if (self::_sendHttp ($post_values,$this->paths['printers'])) + if(self::_parseServerOutput()) + self::_parseAttributes(); + + + if (isset($this->serveroutput) && isset($this->serveroutput->status)) { + + $this->status = array_merge($this->status,array($this->serveroutput->status)); + + if ($this->serveroutput->status == "successfull-ok") + self::_errorLog("validate job: ".$this->serveroutput->status,3); + else + self::_errorLog("validate job: ".$this->serveroutput->status,1); + + return $this->serveroutput->status; + + } + + $this->status = array_merge($this->status,array("OPERATION FAILED")); + self::_errorLog("validate job : OPERATION FAILED",3); + + return false; + } + // }}} + + // {{{ getPrinterAttributes() + public function getPrinterAttributes() { + + $this->jobs = array_merge($this->jobs,array("")); + $this->jobs_uri = array_merge($this->jobs_uri,array("")); + + $jobattributes = ''; + $operationattributes = ''; + self::_buildValues($operationattributes,$jobattributes,$printerattributes); + self::_setOperationId(); + $this->parsed = array(); + unset($this->printer_attributes); + + if (!isset($this->setup->uri)) { + $this->getPrinters(); + unset($this->jobs[count($this->jobs) - 1]); + unset($this->jobs_uri[count($this->jobs_uri) - 1]); + unset($this->status[count($this->status) - 1]); + + if (array_key_exists(0,$this->available_printers)) + self::setPrinterURI($this->available_printers[0]); + else { + trigger_error(_("_stringJob: Printer URI is not set: die"),E_USER_WARNING); + self::_putDebug( _("_stringJob: Printer URI is not set: die\n"),3); + self::_errorLog(" Printer URI is not set, die",2); + return FALSE; + } + } + + if (!isset($this->setup->charset)) + self::setCharset('us-ascii'); + + if (!isset($this->setup->language)) + self::setLanguage('en_us'); + + if (!isset($this->meta->username)) + self::setUserName(); + + $this->stringjob = chr(0x01) . chr(0x01) // 1.1 | version-number + . chr(0x00) . chr (0x0b) // Print-URI | operation-id + . $this->meta->operation_id // request-id + . chr(0x01) // start operation-attributes | operation-attributes-tag + . $this->meta->charset + . $this->meta->language + . $this->meta->printer_uri + . $this->meta->username + . $printerattributes + . chr(0x03); // end-of-attributes | end-of-attributes-tag + + self::_putDebug(sprintf(_("String sent to the server is:\n%s\n"), $this->stringjob)); + + self::_putDebug(sprintf(_("Getting printer attributes of %s\n"),$this->printer_uri),2); + + $this->output = $this->stringjob; + + $post_values = array( "Content-Type"=>"application/ipp", + "Data"=>$this->output); + + if (self::_sendHttp ($post_values,$this->paths['root'])) + if (self::_parseServerOutput()) + self::_parsePrinterAttributes(); + + $this->attributes = &$this->printer_attributes; + + if (isset($this->serveroutput) && isset($this->serveroutput->status)) { + + $this->status = array_merge($this->status,array($this->serveroutput->status)); + + if ($this->serveroutput->status == "successfull-ok") + self::_errorLog(sprintf(_("getting printer attributes of %s: %s"),$this->printer_uri, + $this->serveroutput->status),3); + else + self::_errorLog(sprintf(_("getting printer attributes of %s: %s"),$this->printer_uri, + $this->serveroutput->status),1); + + return $this->serveroutput->status; + } + + $this->status = array_merge($this->status,array("OPERATION FAILED")); + self::_errorLog(date("Y-m-d H:i:s : ") + .basename($_SERVER['PHP_SELF']) + .sprintf(_("getting printer's attributes of %s : OPERATION FAILED"), + $this->printer_uri),3); + + return false; + } + // }}} + + // {{{ getJobs ($my_jobs=true,$limit=0,$which_jobs=""); + public function getJobs($my_jobs=true,$limit=0,$which_jobs="not-completed",$subset=false) { + + $this->jobs = array_merge($this->jobs,array("")); + $this->jobs_uri = array_merge($this->jobs_uri,array("")); + + self::_setOperationId(); + $this->parsed = array(); + unset($this->printer_attributes); + + if (!isset($this->setup->uri)) { + $this->getPrinters(); + unset($this->jobs[count($this->jobs) - 1]); + unset($this->jobs_uri[count($this->jobs_uri) - 1]); + unset($this->status[count($this->status) - 1]); + + if (array_key_exists(0,$this->available_printers)) + self::setPrinterURI($this->available_printers[0]); + else { + trigger_error(_("getJobs: Printer URI is not set: die"),E_USER_WARNING); + self::_putDebug( _("_stringJob: Printer URI is not set: die\n"),3); + self::_errorLog("getJobs: Printer URI is not set, die",2); + return FALSE; + } + } + + if (!isset($this->setup->charset)) + self::setCharset('us-ascii'); + + if (!isset($this->setup->language)) + self::setLanguage('en_us'); + + if (!isset($this->meta->username)) + self::setUserName(); + + if ($limit) { + $limit = self::_integerBuild($limit); + $this->meta->limit = chr(0x21) // integer + . self::_giveMeStringLength('limit') + . 'limit' + . self::_giveMeStringLength($limit) + . $limit; + } else + $this->meta->limit = ''; + + if ($which_jobs == 'completed') + $this->meta->which_jobs = chr(0x44) // keyword + . self::_giveMeStringLength('which-jobs') + . 'which-jobs' + . self::_giveMeStringLength($which_jobs) + . $which_jobs; + else + $this->meta->which_jobs = ""; + + if ($my_jobs) + $this->meta->my_jobs = chr(0x22) // boolean + . self::_giveMeStringLength('my-jobs') + . 'my-jobs' + . self::_giveMeStringLength(chr(0x01)) + . chr(0x01); + else + $this->meta->my_jobs = ''; + + $this->stringjob = chr(0x01) . chr(0x01) // 1.1 | version-number + . chr(0x00) . chr (0x0A) // Get-Jobs | operation-id + . $this->meta->operation_id // request-id + . chr(0x01) // start operation-attributes | operation-attributes-tag + . $this->meta->charset + . $this->meta->language + . $this->meta->printer_uri + . $this->meta->username + . $this->meta->limit + . $this->meta->which_jobs + . $this->meta->my_jobs + ; + if ($subset) + $this->stringjob .= + chr(0x44) // keyword + . self::_giveMeStringLength('requested-attributes') + . 'requested-attributes' + . self::_giveMeStringLength('job-uri') + . 'job-uri' + . chr(0x44) // keyword + . self::_giveMeStringLength('') + . '' + . self::_giveMeStringLength('job-name') + . 'job-name' + . chr(0x44) // keyword + . self::_giveMeStringLength('') + . '' + . self::_giveMeStringLength('job-state') + . 'job-state' + . chr(0x44) // keyword + . self::_giveMeStringLength('') + . '' + . self::_giveMeStringLength('job-state-reason') + . 'job-state-reason' + ; + $this->stringjob .= chr(0x03); // end-of-attributes | end-of-attributes-tag + + self::_putDebug(sprintf(_("String sent to the server is:\n%s\n"), $this->stringjob)); + + self::_putDebug(sprintf(_("getting jobs of %s\n"),$this->printer_uri),2); + + $this->output = $this->stringjob; + + $post_values = array( "Content-Type"=>"application/ipp", + "Data"=>$this->output); + + if (self::_sendHttp ($post_values,$this->paths['jobs'])) + if (self::_parseServerOutput()) + self::_parseJobsAttributes(); + + $this->attributes = &$this->jobs_attributes; + + + if (isset($this->serveroutput) && isset($this->serveroutput->status)) { + + $this->status = array_merge($this->status,array($this->serveroutput->status)); + + if ($this->serveroutput->status == "successfull-ok") + self::_errorLog(sprintf(_("getting jobs of printer %s: "),$this->printer_uri) + .$this->serveroutput->status,3); + else + self::_errorLog(sprintf(_("getting jobs of printer %s: "),$this->printer_uri) + .$this->serveroutput->status,1); + + return $this->serveroutput->status; + } + + $this->status = array_merge($this->status,array("OPERATION FAILED")); + self::_errorLog(date("Y-m-d H:i:s : ") + .basename($_SERVER['PHP_SELF']) + .sprintf(_("getting jobs of %s : OPERATION FAILED"), + $this->printer_uri),3); + + return false; + } + // }}} + + // {{{ getJobAttributes ($job_uri,subset="false",$attributes_group="all"); + public function getJobAttributes($job_uri,$subset=false,$attributes_group="all") { + + $this->jobs = array_merge($this->jobs,array("")); + $this->jobs_uri = array_merge($this->jobs_uri,array("")); + + if (!$job_uri) { + trigger_error(_("getJobAttributes: Job URI is not set, die.")); + return FALSE; + } + + self::_setOperationId(); + $this->parsed = array(); + unset($this->printer_attributes); + + if (!isset($this->setup->uri)) { + $this->getPrinters(); + unset($this->jobs[count($this->jobs) - 1]); + unset($this->jobs_uri[count($this->jobs_uri) - 1]); + unset($this->status[count($this->status) - 1]); + + if (array_key_exists(0,$this->available_printers)) + self::setPrinterURI($this->available_printers[0]); + else { + trigger_error(_("getJobs: Printer URI is not set: die"),E_USER_WARNING); + self::_putDebug( _("_stringJob: Printer URI is not set: die\n"),3); + self::_errorLog("getJobs: Printer URI is not set, die",2); + return FALSE; + } + } + + if (!isset($this->setup->charset)) + self::setCharset('us-ascii'); + + if (!isset($this->setup->language)) + self::setLanguage('en_us'); + + if (!isset($this->meta->username)) + self::setUserName(); + + $this->meta->job_uri = chr(0x45) // URI + . self::_giveMeStringLength('job-uri') + . 'job-uri' + . self::_giveMeStringLength($job_uri) + . $job_uri; + + $this->stringjob = chr(0x01) . chr(0x01) // 1.1 | version-number + . chr(0x00) . chr (0x09) // Get-Job-Attributes | operation-id + . $this->meta->operation_id // request-id + . chr(0x01) // start operation-attributes | operation-attributes-tag + . $this->meta->charset + . $this->meta->language + . $this->meta->job_uri + . $this->meta->username + ; + if ($subset) + $this->stringjob .= + chr(0x44) // keyword + . self::_giveMeStringLength('requested-attributes') + . 'requested-attributes' + . self::_giveMeStringLength('job-uri') + . 'job-uri' + . chr(0x44) // keyword + . self::_giveMeStringLength('') + . '' + . self::_giveMeStringLength('job-name') + . 'job-name' + . chr(0x44) // keyword + . self::_giveMeStringLength('') + . '' + . self::_giveMeStringLength('job-state') + . 'job-state' + . chr(0x44) // keyword + . self::_giveMeStringLength('') + . '' + . self::_giveMeStringLength('job-state-reason') + . 'job-state-reason' + ; + elseif($attributes_group) { + switch($attributes_group) { + case 'job-template': + break; + case 'job-description': + break; + case 'all': + break; + default: + trigger_error(_('not a valid attribute group: ').$attributes_group,E_USER_NOTICE); + $attributes_group = ''; + break; + } + $this->stringjob .= + chr(0x44) // keyword + . self::_giveMeStringLength('requested-attributes') + . 'requested-attributes' + . self::_giveMeStringLength($attributes_group) + . $attributes_group; + } + $this->stringjob .= chr(0x03); // end-of-attributes | end-of-attributes-tag + + self::_putDebug(sprintf(_("String sent to the server is:\n%s\n"), $this->stringjob)); + + self::_putDebug(sprintf(_("getting jobs of %s\n"),$this->printer_uri),2); + + $this->output = $this->stringjob; + + $post_values = array( "Content-Type"=>"application/ipp", + "Data"=>$this->output); + + if (self::_sendHttp ($post_values,$this->paths['jobs'])) + if (self::_parseServerOutput()) + self::_parseJobAttributes(); + + $this->attributes = &$this->job_attributes; + + if (isset($this->serveroutput) && isset($this->serveroutput->status)) { + + $this->status = array_merge($this->status,array($this->serveroutput->status)); + + if ($this->serveroutput->status == "successfull-ok") + self::_errorLog(sprintf(_("getting job attributes for %s: "),$job_uri) + .$this->serveroutput->status,3); + else + self::_errorLog(sprintf(_("getting job attributes for %s: "),$job_uri) + .$this->serveroutput->status,1); + + return $this->serveroutput->status; + } + + $this->status = array_merge($this->status,array("OPERATION FAILED")); + self::_errorLog(date("Y-m-d H:i:s : ") + .basename($_SERVER['PHP_SELF']) + .sprintf(_("getting jobs attributes of %s : OPERATION FAILED"), + $job_uri),3); + + return false; + } + + // }}} + + // {{{ getPrinters(); + public function getPrinters() { + + // placeholder for vendor extension operation (getAvailablePrinters for CUPS) + $this->jobs = array_merge($this->jobs,array('')); + $this->jobs_uri = array_merge($this->jobs_uri,array('')); + $this->status = array_merge($this->status,array('')); + } + // }}} + +/****************** +* +* DEVELOPPEMENT FUNCTIONS +* +*******************/ + + // {{{ generateError($error) + public function generateError ($error) { + switch ($error) { + case "request_body_malformed": + $this->error_generation->request_body_malformed = chr(0xFF); + break; + default: + true; + break; + } + // }}} + + // {{{ resetError ($error) + trigger_error(sprintf(_('Setting Error %s'),$error),E_USER_NOTICE); + } + + public function resetError ($error) { + unset ($this->error_generation->$error); + trigger_error(sprintf(_('Reset Error %s'),$error),E_USER_NOTICE); + } + // }}} + +/****************** +* +* PROTECTED FUNCTIONS +* +*******************/ + +// SETUP + + // {{{ _setOperationId () + protected function _setOperationId () { + $prepend = ''; + $this->operation_id += 1; + $this->meta->operation_id = self::_integerBuild($this->operation_id); + self::_putDebug( "operation id is: ".$this->operation_id."\n",2); + } + // }}} + + // {{{ _setJobId() + protected function _setJobId() { + + $this->meta->jobid +=1; + $prepend = ''; + $prepend_length = 4 - strlen($this->meta->jobid); + for ($i = 0; $i < $prepend_length ; $i++ ) + $prepend .= '0'; + + return $prepend.$this->meta->jobid; + } + // }}} + + // {{{ _setJobUri ($job_uri) + protected function _setJobUri ($job_uri) { + + $this->meta->job_uri = chr(0x45) // type uri + . chr(0x00).chr(0x07) // name-length + . "job-uri" + //. chr(0x00).chr(strlen($job_uri)) + . self::_giveMeStringLength($job_uri) + . $job_uri; + + self::_putDebug( "job-uri is: ".$job_uri."\n",2); + } + // }}} + +// RESPONSE PARSING + + // {{{ _parsePrinterAttributes() + protected function _parsePrinterAttributes() { + + //if (!preg_match('#successful#',$this->serveroutput->status)) + // return false; + + $k = -1; + for ($i = 0 ; $i < count($this->serveroutput->response) ; $i++) + for ($j = 0 ; $j < (count($this->serveroutput->response[$i]) - 1) ; $j ++) + if (!empty($this->serveroutput->response[$i][$j]['name'])) { + $k++; + $l = 0; + $this->parsed[$k]['range'] = $this->serveroutput->response[$i]['attributes']; + $this->parsed[$k]['name'] = $this->serveroutput->response[$i][$j]['name']; + $this->parsed[$k]['type'] = $this->serveroutput->response[$i][$j]['type']; + $this->parsed[$k][$l] = $this->serveroutput->response[$i][$j]['value']; + } else { + $l ++; + $this->parsed[$k][$l] = $this->serveroutput->response[$i][$j]['value']; + } + $this->serveroutput->response = array(); + + $this->printer_attributes = new stdClass(); + for ($i = 0 ; $i < count($this->parsed) ; $i ++) { + $name = $this->parsed[$i]['name']; + $php_name = str_replace('-','_',$name); + $type = $this->parsed[$i]['type']; + $range = $this->parsed[$i]['range']; + $this->printer_attributes->$php_name = new stdClass(); + $this->printer_attributes->$php_name->_type = $type; + $this->printer_attributes->$php_name->_range = $range; + for ($j = 0 ; $j < (count($this->parsed[$i]) - 3) ; $j ++) { + $value = $this->parsed[$i][$j]; + $index = '_value'.$j; + $this->printer_attributes->$php_name->$index = $value; + } + } + + $this->parsed = array(); + + + } + // }}} + + // {{{ _parseJobsAttributes() + protected function _parseJobsAttributes() { + + //if ($this->serveroutput->status != "successfull-ok") + // return false; + + $job = -1; + for ($i = 0 ; $i < count($this->serveroutput->response) ; $i++) { + if ($this->serveroutput->response[$i]['attributes'] == "job-attributes") + $job ++; + $k = -1; + for ($j = 0 ; $j < (count($this->serveroutput->response[$i]) - 1) ; $j ++) + if (!empty($this->serveroutput->response[$i][$j]['name'])) { + $k++; + $l = 0; + $this->parsed[$job][$k]['range'] = $this->serveroutput->response[$i]['attributes']; + $this->parsed[$job][$k]['name'] = $this->serveroutput->response[$i][$j]['name']; + $this->parsed[$job][$k]['type'] = $this->serveroutput->response[$i][$j]['type']; + $this->parsed[$job][$k][$l] = $this->serveroutput->response[$i][$j]['value']; + } else { + $l ++; + $this->parsed[$job][$k][$l] = $this->serveroutput->response[$i][$j]['value']; + } + } + + $this->serveroutput->response = array(); + $this->jobs_attributes = new stdClass(); + for ($job_nbr = 0 ; $job_nbr <= $job ; $job_nbr ++) { + $job_index = "job_".$job_nbr; + $this->jobs_attributes->$job_index = new stdClass(); + for ($i = 0 ; $i < count($this->parsed[$job_nbr]) ; $i ++) { + $name = $this->parsed[$job_nbr][$i]['name']; + $php_name = str_replace('-','_',$name); + $type = $this->parsed[$job_nbr][$i]['type']; + $range = $this->parsed[$job_nbr][$i]['range']; + $this->jobs_attributes->$job_index->$php_name = new stdClass(); + $this->jobs_attributes->$job_index->$php_name->_type = $type; + $this->jobs_attributes->$job_index->$php_name->_range = $range; + for ($j = 0 ; $j < (count($this->parsed[$job_nbr][$i]) - 3) ; $j ++) { + $value = self::_interpretAttribute($name,$type,$this->parsed[$job_nbr][$i][$j]); + $index = '_value'.$j; + $this->jobs_attributes->$job_index->$php_name->$index = $value; + } + } + } + + $this->parsed = array(); + + + } + // }}} + + // {{{ _readAttribute($attributes_type,$ji,&$collection=false) + protected function _readAttribute($attributes_type) { + + $tag = ord($this->serveroutput->body[$this->_parsing->offset]); + + $this->_parsing->offset += 1; + $j = $this->index; + + $tag = self::_readTag($tag); + + switch ($tag) { + case "begCollection": //RFC3382 (BLIND CODE) + if ($this->end_collection) + $this->index --; + $this->end_collection = false; + $this->serveroutput->response[$attributes_type][$j]['type'] = "collection"; + self::_putDebug( "tag is: begCollection\n"); + self::_readAttributeName ($attributes_type,$j); + if (!$this->serveroutput->response[$attributes_type][$j]['name']) { // it is a multi-valued collection + $this->collection_depth ++; + $this->index --; + $this->collection_nbr[$this->collection_depth] ++; + } else { + $this->collection_depth ++; + if ($this->collection_depth == 0) + $this->collection = (object) 'collection'; + if (array_key_exists($this->collection_depth,$this->collection_nbr)) + $this->collection_nbr[$this->collection_depth] ++; + else + $this->collection_nbr[$this->collection_depth] = 0; + unset($this->end_collection); + + } + self::_readValue ("begCollection",$attributes_type,$j); + break; + case "endCollection": //RFC3382 (BLIND CODE) + $this->serveroutput->response[$attributes_type][$j]['type'] = "collection"; + self::_putDebug( "tag is: endCollection\n"); + self::_readAttributeName ($attributes_type,$j,0); + self::_readValue ('name',$attributes_type,$j,0); + $this->collection_depth --; + $this->collection_key[$this->collection_depth] = 0; + $this->end_collection = true; + break; + case "memberAttrName": // RFC3382 (BLIND CODE) + $this->serveroutput->response[$attributes_type][$j]['type'] = "memberAttrName"; + $this->index -- ; + self::_putDebug( "tag is: memberAttrName\n"); + self::_readCollection ($attributes_type,$j); + break; + + default: + $this->collection_depth = -1; + $this->collection_key = array(); + $this->collection_nbr = array(); + $this->serveroutput->response[$attributes_type][$j]['type'] = $tag; + self::_putDebug( "tag is: $tag\n"); + $attribute_name = self::_readAttributeName ($attributes_type,$j); + if (!$attribute_name) + $attribute_name = $this->attribute_name; + else + $this->attribute_name = $attribute_name; + $value = self::_readValue ($tag,$attributes_type,$j); + $this->serveroutput->response[$attributes_type][$j]['value'] = + self::_interpretAttribute($attribute_name,$tag,$this->serveroutput->response[$attributes_type][$j]['value']); + break; + + } + return; + } + // }}} + + // {{{ _readTag($tag) + protected function _readTag($tag) { + + switch ($tag) { + case 0x10: + $tag = "unsupported"; + break; + case 0x11: + $tag = "reserved for 'default'"; + break; + case 0x12: + $tag = "unknown"; + break; + case 0x13: + $tag = "no-value"; + break; + case 0x15: // RFC 3380 + $tag = "not-settable"; + break; + case 0x16: // RFC 3380 + $tag = "delete-attribute"; + break; + case 0x17: // RFC 3380 + $tag = "admin-define"; + break; + case 0x20: + $tag = "IETF reserved (generic integer)"; + break; + case 0x21: + $tag = "integer"; + break; + case 0x22: + $tag = "boolean"; + break; + case 0x23: + $tag = "enum"; + break; + case 0x30: + $tag = "octetString"; + break; + case 0x31: + $tag = "datetime"; + break; + case 0x32: + $tag = "resolution"; + break; + case 0x33: + $tag = "rangeOfInteger"; + break; + case 0x34: //RFC3382 (BLIND CODE) + $tag = "begCollection"; + break; + case 0x35: + $tag = "textWithLanguage"; + break; + case 0x36: + $tag = "nameWithLanguage"; + break; + case 0x37: //RFC3382 (BLIND CODE) + $tag = "endCollection"; + break; + case 0x40: + $tag = "IETF reserved text string"; + break; + case 0x41: + $tag = "textWithoutLanguage"; + break; + case 0x42: + $tag = "nameWithoutLanguage"; + break; + case 0x43: + $tag = "IETF reserved for future"; + break; + case 0x44: + $tag = "keyword"; + break; + case 0x45: + $tag = "uri"; + break; + case 0x46: + $tag = "uriScheme"; + break; + case 0x47: + $tag = "charset"; + break; + case 0x48: + $tag = "naturalLanguage"; + break; + case 0x49: + $tag = "mimeMediaType"; + break; + case 0x4A: // RFC3382 (BLIND CODE) + $tag = "memberAttrName"; + break; + case 0x7F: + $tag = "extended type"; + break; + default: + + if ($tag >= 0x14 && $tag < 0x15 && $tag > 0x17 && $tag <= 0x1f) + $tag = "out-of-band"; + elseif (0x24 <= $tag && $tag <= 0x2f) + $tag = "new integer type"; + elseif (0x38 <= $tag && $tag <= 0x3F) + $tag = "new octet-stream type"; + elseif (0x4B <= $tag && $tag <= 0x5F) + $tag = "new character string type"; + elseif ((0x60 <= $tag && $tag < 0x7f) || $tag >= 0x80 ) + $tag = "IETF reserved for future"; + else + $tag = sprintf("UNKNOWN: 0x%x (%u)",$tag,$tag); + + break; + } + return $tag; + } + // }}} + + // {{{ _readCollection($attributes_type,$j,&$collection) + protected function _readCollection($attributes_type,$j) { + + $name_length = ord($this->serveroutput->body[$this->_parsing->offset]) * 256 + + ord($this->serveroutput->body[$this->_parsing->offset + 1]); + + $this->_parsing->offset += 2; + + self::_putDebug( "Collection name_length ". $name_length ."\n"); + + $name = ''; + for ($i = 0; $i < $name_length; $i++) { + $name .= $this->serveroutput->body[$this->_parsing->offset]; + $this->_parsing->offset += 1; + if ($this->_parsing->offset > strlen($this->serveroutput->body)) + return; + } + + $collection_name = $name; + + $name_length = ord($this->serveroutput->body[$this->_parsing->offset]) * 256 + + ord($this->serveroutput->body[$this->_parsing->offset + 1]); + $this->_parsing->offset += 2; + + self::_putDebug( "Attribute name_length ". $name_length ."\n"); + + $name = ''; + for ($i = 0; $i < $name_length; $i++) { + $name .= $this->serveroutput->body[$this->_parsing->offset]; + $this->_parsing->offset += 1; + if ($this->_parsing->offset > strlen($this->serveroutput->body)) + return; + } + + $attribute_name = $name; + if ($attribute_name == "") { + $attribute_name = $this->last_attribute_name; + $this->collection_key[$this->collection_depth] ++; + } else { + $this->collection_key[$this->collection_depth] = 0; + } + $this->last_attribute_name = $attribute_name; + + self::_putDebug( "Attribute name ".$name."\n"); + + $tag = self::_readTag(ord($this->serveroutput->body[$this->_parsing->offset])); + $this->_parsing->offset ++; + + $type = $tag; + + $name_length = ord($this->serveroutput->body[$this->_parsing->offset]) * 256 + + ord($this->serveroutput->body[$this->_parsing->offset + 1]); + $this->_parsing->offset += 2; + + self::_putDebug( "Collection2 name_length ". $name_length ."\n"); + + $name = ''; + for ($i = 0; $i < $name_length; $i++) { + $name .= $this->serveroutput->body[$this->_parsing->offset]; + $this->_parsing->offset += 1; + if ($this->_parsing->offset > strlen($this->serveroutput->body)) + return; + } + + $collection_value = $name; + $value_length = ord($this->serveroutput->body[$this->_parsing->offset]) * 256 + + ord($this->serveroutput->body[$this->_parsing->offset + 1]); + + self::_putDebug( "Collection value_length ".$this->serveroutput->body[ $this->_parsing->offset] + . $this->serveroutput->body[$this->_parsing->offset + 1] + .": " + . $value_length + . " "); + + $this->_parsing->offset += 2; + + $value = ''; + for ($i = 0; $i < $value_length; $i++) { + + if ($this->_parsing->offset >= strlen($this->serveroutput->body)) + return; + $value .= $this->serveroutput->body[$this->_parsing->offset]; + $this->_parsing->offset += 1; + + } + + $object = &$this->collection; + for ($i = 0 ; $i <= $this->collection_depth ; $i ++) { + $indice = "_indice".$this->collection_nbr[$i]; + if (!isset($object->$indice)) + $object->$indice = (object) 'indice'; + $object = &$object->$indice; + } + + $value_key = "_value".$this->collection_key[$this->collection_depth]; + $col_name_key = "_collection_name".$this->collection_key[$this->collection_depth]; + $col_val_key = "_collection_value".$this->collection_key[$this->collection_depth]; + + $attribute_value = self::_interpretAttribute($attribute_name,$tag,$value); + $attribute_name = str_replace('-','_',$attribute_name); + + + self::_putDebug( sprintf("Value: %s\n",$value)); + $object->$attribute_name->_type = $type; + $object->$attribute_name->$value_key = $attribute_value; + $object->$attribute_name->$col_name_key = $collection_name; + $object->$attribute_name->$col_val_key = $collection_value; + + $this->serveroutput->response[$attributes_type][$j]['value'] = $this->collection; + } + // }}} + + // {{{ _readAttributeName ($attributes_type,$j) + protected function _readAttributeName ($attributes_type,$j,$write=1) { + + $name_length = ord($this->serveroutput->body[ $this->_parsing->offset]) * 256 + + ord($this->serveroutput->body[$this->_parsing->offset + 1]); + $this->_parsing->offset += 2; + + self::_putDebug( "name_length ". $name_length ."\n"); + + $name = ''; + for ($i = 0; $i < $name_length; $i++) { + if ($this->_parsing->offset >= strlen($this->serveroutput->body)) + return; + $name .= $this->serveroutput->body[$this->_parsing->offset]; + $this->_parsing->offset += 1; + } + + if($write) + $this->serveroutput->response[$attributes_type][$j]['name'] = $name; + + self::_putDebug( "name " . $name . "\n"); + + return $name; + } + // }}} + + // {{{ _readValue ($type,$attributes_type,$j) + protected function _readValue ($type,$attributes_type,$j,$write=1) { + + $value_length = ord($this->serveroutput->body[$this->_parsing->offset]) * 256 + + ord($this->serveroutput->body[$this->_parsing->offset + 1]); + + self::_putDebug( "value_length ".$this->serveroutput->body[ $this->_parsing->offset] + . $this->serveroutput->body[$this->_parsing->offset + 1] + .": " + . $value_length + . " "); + + $this->_parsing->offset += 2; + + $value = ''; + for ($i = 0; $i < $value_length; $i++) { + + if ($this->_parsing->offset >= strlen($this->serveroutput->body)) + return; + $value .= $this->serveroutput->body[$this->_parsing->offset]; + $this->_parsing->offset += 1; + + } + + self::_putDebug( sprintf("Value: %s\n",$value)); + + if ($write) + $this->serveroutput->response[$attributes_type][$j]['value'] = $value; + + return $value; + } + // }}} + + // {{{ _parseAttributes() + protected function _parseAttributes() { + + $k = -1; + for ($i = 0 ; $i < count($this->serveroutput->response) ; $i++) + for ($j = 0 ; $j < (count($this->serveroutput->response[$i]) - 1) ; $j ++) + if (!empty($this->serveroutput->response[$i][$j]['name'])) { + $k++; + $l = 0; + $this->parsed[$k]['range'] = $this->serveroutput->response[$i]['attributes']; + $this->parsed[$k]['name'] = $this->serveroutput->response[$i][$j]['name']; + $this->parsed[$k]['type'] = $this->serveroutput->response[$i][$j]['type']; + $this->parsed[$k][$l] = $this->serveroutput->response[$i][$j]['value']; + } else { + $l ++; + $this->parsed[$k][$l] = $this->serveroutput->response[$i][$j]['value']; + } + $this->serveroutput->response = array(); + $this->attributes = new stdClass(); + for ($i = 0 ; $i < count($this->parsed) ; $i ++) { + $name = $this->parsed[$i]['name']; + $php_name = str_replace('-','_',$name); + $type = $this->parsed[$i]['type']; + $range = $this->parsed[$i]['range']; + $this->attributes->$php_name = new stdClass(); + $this->attributes->$php_name->_type = $type; + $this->attributes->$php_name->_range = $range; + for ($j = 0 ; $j < (count($this->parsed[$i]) - 3) ; $j ++) { + $value = $this->parsed[$i][$j]; + $index = '_value'.$j; + $this->attributes->$php_name->$index = $value; + } + } + + $this->parsed = array(); + + } + // }}} + + // {{{ _parseJobAttributes() + protected function _parseJobAttributes() { + + //if (!preg_match('#successful#',$this->serveroutput->status)) + // return false; + + $k = -1; + for ($i = 0 ; $i < count($this->serveroutput->response) ; $i++) + for ($j = 0 ; $j < (count($this->serveroutput->response[$i]) - 1) ; $j ++) + if (!empty($this->serveroutput->response[$i][$j]['name'])) { + $k++; + $l = 0; + $this->parsed[$k]['range'] = $this->serveroutput->response[$i]['attributes']; + $this->parsed[$k]['name'] = $this->serveroutput->response[$i][$j]['name']; + $this->parsed[$k]['type'] = $this->serveroutput->response[$i][$j]['type']; + $this->parsed[$k][$l] = $this->serveroutput->response[$i][$j]['value']; + } else { + $l ++; + $this->parsed[$k][$l] = $this->serveroutput->response[$i][$j]['value']; + } + + $this->serveroutput->response = array(); + + $this->job_attributes = new stdClass(); + for ($i = 0 ; $i < count($this->parsed) ; $i ++) { + $name = $this->parsed[$i]['name']; + $php_name = str_replace('-','_',$name); + $type = $this->parsed[$i]['type']; + $range = $this->parsed[$i]['range']; + $this->job_attributes->$php_name = new stdClass(); + $this->job_attributes->$php_name->_type = $type; + $this->job_attributes->$php_name->_range = $range; + for ($j = 0 ; $j < (count($this->parsed[$i]) - 3) ; $j ++) { + $value = $this->parsed[$i][$j]; + $index = '_value'.$j; + $this->job_attributes->$php_name->$index = $value; + } + } + + $this->parsed = array(); + + + } + // }}} + + // {{{ _interpretAttribute($attribute_name,$type,$value) + protected function _interpretAttribute($attribute_name,$type,$value) { + + switch ($type) { + case "integer": + $value = self::_interpretInteger($value); + break; + case "rangeOfInteger": + $value = self::_interpretRangeOfInteger($value); + break; + case 'boolean': + $value = ord($value); + if ($value == 0x00) + $value = 'false'; + else + $value = 'true'; + break; + case 'datetime': + $value = self::_interpretDateTime($value); + break; + case 'enum': + $value = $this->_interpretEnum($attribute_name,$value); // must be overwritten by children + break; + case 'resolution': + $unit = $value[8]; + $value = self::_interpretRangeOfInteger(substr($value,0,8)); + switch($unit) { + case chr(0x03): + $unit = "dpi"; + break; + case chr(0x04): + $unit = "dpc"; + break; + } + $value = $value." ".$unit; + break; + default: + break; + } + return $value; + } + // }}} + + // {{{ _interpretRangeOfInteger($value) + protected function _interpretRangeOfInteger($value) { + + $value_parsed = 0; + $integer1 = $integer2 = 0; + + $halfsize = strlen($value) / 2; + + $integer1 = self::_interpretInteger(substr($value,0,$halfsize)); + $integer2 = self::_interpretInteger(substr($value,$halfsize,$halfsize)); + + $value_parsed = sprintf('%s-%s',$integer1,$integer2); + + + return $value_parsed; + } + // }}} + + // {{{ _interpretDateTime($date) { + protected function _interpretDateTime($date) { + $year = self::_interpretInteger(substr($date,0,2)); + $month = self::_interpretInteger(substr($date,2,1)); + $day = self::_interpretInteger(substr($date,3,1)); + $hour = self::_interpretInteger(substr($date,4,1)); + $minute = self::_interpretInteger(substr($date,5,1)); + $second = self::_interpretInteger(substr($date,6,1)); + $direction = substr($date,8,1); + $hours_from_utc = self::_interpretInteger(substr($date,9,1)); + $minutes_from_utc = self::_interpretInteger(substr($date,10,1)); + + $date = sprintf('%s-%s-%s %s:%s:%s %s%s:%s',$year,$month,$day,$hour,$minute,$second,$direction,$hours_from_utc,$minutes_from_utc); + + return $date; + } + // }}} + + // {{{ _interpretEnum() + protected function _interpretEnum($attribute_name,$value) { + + $value_parsed = self::_interpretInteger($value); + + switch ($attribute_name) { + case 'job-state': + switch ($value_parsed) { + case 0x03: + $value = 'pending'; + break; + case 0x04: + $value = 'pending-held'; + break; + case 0x05: + $value = 'processing'; + break; + case 0x06: + $value = 'processing-stopped'; + break; + case 0x07: + $value = 'canceled'; + break; + case 0x08: + $value = 'aborted'; + break; + case 0x09: + $value = 'completed'; + break; + } + if ($value_parsed > 0x09) + $value = sprintf('Unknown(IETF standards track "job-state" reserved): 0x%x',$value_parsed); + break; + case 'print-quality': + case 'print-quality-supported': + case 'print-quality-default': + switch ($value_parsed) { + case 0x03: + $value = 'draft'; + break; + case 0x04: + $value = 'normal'; + break; + case 0x05: + $value = 'high'; + break; + } + break; + case 'printer-state': + switch ($value_parsed) { + case 0x03: + $value = 'idle'; + break; + case 0x04: + $value = 'processing'; + break; + case 0x05: + $value = 'stopped'; + break; + } + if ($value_parsed > 0x05) + $value = sprintf('Unknown(IETF standards track "printer-state" reserved): 0x%x',$value_parsed); + break; + + case 'operations-supported': + switch($value_parsed) { + case 0x0000: + case 0x0001: + $value = sprintf('Unknown(reserved) : %s',ord($value)); + break; + case 0x0002: + $value = 'Print-Job'; + break; + case 0x0003: + $value = 'Print-URI'; + break; + case 0x0004: + $value = 'Validate-Job'; + break; + case 0x0005: + $value = 'Create-Job'; + break; + case 0x0006: + $value = 'Send-Document'; + break; + case 0x0007: + $value = 'Send-URI'; + break; + case 0x0008: + $value = 'Cancel-Job'; + break; + case 0x0009: + $value = 'Get-Job-Attributes'; + break; + case 0x000A: + $value = 'Get-Jobs'; + break; + case 0x000B: + $value = 'Get-Printer-Attributes'; + break; + case 0x000C: + $value = 'Hold-Job'; + break; + case 0x000D: + $value = 'Release-Job'; + break; + case 0x000E: + $value = 'Restart-Job'; + break; + case 0x000F: + $value = 'Unknown(reserved for a future operation)'; + break; + case 0x0010: + $value = 'Pause-Printer'; + break; + case 0x0011: + $value = 'Resume-Printer'; + break; + case 0x0012: + $value = 'Purge-Jobs'; + break; + case 0x0013: + $value = 'Set-Printer-Attributes'; // RFC3380 + break; + case 0x0014: + $value = 'Set-Job-Attributes'; // RFC3380 + break; + case 0x0015: + $value = 'Get-Printer-Supported-Values'; // RFC3380 + break; + case 0x0016: + $value = 'Create-Printer-Subscriptions'; + break; + case 0x0017: + $value = 'Create-Job-Subscriptions'; + break; + case 0x0018: + $value = 'Get-Subscription-Attributes'; + break; + case 0x0019: + $value = 'Get-Subscriptions'; + break; + case 0x001A: + $value = 'Renew-Subscription'; + break; + case 0x001B: + $value = 'Cancel-Subscription'; + break; + case 0x001C: + $value = 'Get-Notifications'; + break; + case 0x001D: + $value = sprintf('Unknown (reserved IETF "operations"): 0x%x',ord($value)); + break; + case 0x001E: + $value = sprintf('Unknown (reserved IETF "operations"): 0x%x',ord($value)); + break; + case 0x001F: + $value = sprintf('Unknown (reserved IETF "operations"): 0x%x',ord($value)); + break; + case 0x0020: + $value = sprintf('Unknown (reserved IETF "operations"): 0x%x',ord($value)); + break; + case 0x0021: + $value = sprintf('Unknown (reserved IETF "operations"): 0x%x',ord($value)); + break; + case 0x0022: + $value = 'Enable-Printer'; + break; + case 0x0023: + $value = 'Disable-Printer'; + break; + case 0x0024: + $value = 'Pause-Printer-After-Current-Job'; + break; + case 0x0025: + $value = 'Hold-New-Jobs'; + break; + case 0x0026: + $value = 'Release-Held-New-Jobs'; + break; + case 0x0027: + $value = 'Deactivate-Printer'; + break; + case 0x0028: + $value = 'Activate-Printer'; + break; + case 0x0029: + $value = 'Restart-Printer'; + break; + case 0x002A: + $value = 'Shutdown-Printer'; + break; + case 0x002B: + $value = 'Startup-Printer'; + break; + } + if ($value_parsed > 0x002B && $value_parsed <= 0x3FFF) + $value = sprintf('Unknown(IETF standards track operations reserved): 0x%x',$value_parsed); + elseif ($value_parsed >= 0x4000 && $value_parsed <= 0x8FFF) { + if (method_exists($this,'_getEnumVendorExtensions')) { + $value = $this->_getEnumVendorExtensions($value_parsed); + } else + $value = sprintf('Unknown(Vendor extension for operations): 0x%x',$value_parsed); + } elseif ($value_parsed > 0x8FFF) + $value = sprintf('Unknown operation (should not exists): 0x%x',$value_parsed); + + break; + case 'finishings': + case 'finishings-default': + case 'finishings-supported': + switch ($value_parsed) { + case 3: + $value = 'none'; + break; + case 4: + $value = 'staple'; + break; + case 5: + $value = 'punch'; + break; + case 6: + $value = 'cover'; + break; + case 7: + $value = 'bind'; + break; + case 8: + $value = 'saddle-stitch'; + break; + case 9: + $value = 'edge-stitch'; + break; + case 20: + $value = 'staple-top-left'; + break; + case 21: + $value = 'staple-bottom-left'; + break; + case 22: + $value = 'staple-top-right'; + break; + case 23: + $value = 'staple-bottom-right'; + break; + case 24: + $value = 'edge-stitch-left'; + break; + case 25: + $value = 'edge-stitch-top'; + break; + case 26: + $value = 'edge-stitch-right'; + break; + case 27: + $value = 'edge-stitch-bottom'; + break; + case 28: + $value = 'staple-dual-left'; + break; + case 29: + $value = 'staple-dual-top'; + break; + case 30: + $value = 'staple-dual-right'; + break; + case 31: + $value = 'staple-dual-bottom'; + break; + } + if ($value_parsed > 31) + $value = sprintf('Unknown(IETF standards track "finishing" reserved): 0x%x',$value_parsed); + break; + + case 'orientation-requested': + case 'orientation-requested-supported': + case 'orientation-requested-default': + switch ($value_parsed) { + case 0x03: + $value = 'portrait'; + break; + case 0x04: + $value = 'landscape'; + break; + case 0x05: + $value = 'reverse-landscape'; + break; + case 0x06: + $value = 'reverse-portrait'; + break; + } + if ($value_parsed > 0x06) + $value = sprintf('Unknown(IETF standards track "orientation" reserved): 0x%x',$value_parsed); + break; + + default: + break; + } + return $value; + } + // }}} + + // {{{ _getJobId () + protected function _getJobId () { + + if (!isset($this->serveroutput->response)) + $this->jobs = array_merge($this->jobs,array('NO JOB')); + + $jobfinded = false; + for ($i = 0 ; (!$jobfinded && array_key_exists($i,$this->serveroutput->response)) ; $i ++) + if (($this->serveroutput->response[$i]['attributes']) == "job-attributes") + for ($j = 0 ; array_key_exists($j,$this->serveroutput->response[$i]) ; $j++) + if ($this->serveroutput->response[$i][$j]['name'] == "job-id") { + $this->last_job = $this->serveroutput->response[$i][$j]['value']; + $this->jobs = array_merge($this->jobs,array($this->serveroutput->response[$i][$j]['value'])); + return; + + } + + } + // }}} + + // {{{ _getJobUri () + protected function _getJobUri () { + + if (!isset($this->jobs_uri)) + $this->jobs_uri = array(); + + $jobfinded = false; + for ($i = 0 ; (!$jobfinded && array_key_exists($i,$this->serveroutput->response)) ; $i ++) + if (($this->serveroutput->response[$i]['attributes']) == "job-attributes") + for ($j = 0 ; array_key_exists($j,$this->serveroutput->response[$i]) ; $j++) + if ($this->serveroutput->response[$i][$j]['name'] == "job-uri") { + $this->last_job = $this->serveroutput->response[$i][$j]['value']; + $this->jobs_uri = array_merge($this->jobs_uri,array($this->last_job)); + return; + + } + $this->last_job = ''; + + } + // }}} + + // {{{ _parseResponse () + protected function _parseResponse () { + $j = -1; + $this->index = 0; + for ($i = $this->_parsing->offset; $i < strlen($this->serveroutput->body) ; $i = $this->_parsing->offset) { + + + $tag = ord($this->serveroutput->body[$this->_parsing->offset]); + + + if ($tag > 0x0F) { + + self::_readAttribute($j); + $this->index ++; + continue; + } + + switch ($tag) { + case 0x01: + $j += 1; + $this->serveroutput->response[$j]['attributes'] = "operation-attributes"; + $this->index = 0; + $this->_parsing->offset += 1; + break; + case 0x02: + $j += 1; + $this->serveroutput->response[$j]['attributes'] = "job-attributes"; + $this->index = 0; + $this->_parsing->offset += 1; + break; + case 0x03: + $j +=1; + $this->serveroutput->response[$j]['attributes'] = "end-of-attributes"; + self::_putDebug( "tag is: ".$this->serveroutput->response[$j]['attributes']."\n"); + if ($this->alert_on_end_tag === 1) + echo "END tag OK
"; + $this->response_completed[(count($this->response_completed) -1)] = "completed"; + return; + case 0x04: + $j += 1; + $this->serveroutput->response[$j]['attributes'] = "printer-attributes"; + $this->index = 0; + $this->_parsing->offset += 1; + break; + case 0x05: + $j += 1; + $this->serveroutput->response[$j]['attributes'] = "unsupported-attributes"; + $this->index = 0; + $this->_parsing->offset += 1; + break; + default: + $j += 1; + $this->serveroutput->response[$j]['attributes'] = sprintf(_("0x%x (%u) : attributes tag Unknown (reserved for future versions of IPP"),$tag,$tag); + $this->index = 0; + $this->_parsing->offset += 1; + break; + } + + self::_putDebug( "tag is: ".$this->serveroutput->response[$j]['attributes']."\n\n\n"); + + } + return; + } + // }}} + + + + + /* + // NOTICE : HAVE TO READ AGAIN RFC 2911 TO SEE IF IT IS PART OF SERVER'S RESPONSE (CUPS DO NOT) + // {{{ _getPrinterUri () + protected function _getPrinterUri () { + + for ($i = 0 ; (array_key_exists($i,$this->serveroutput->response)) ; $i ++) + if (($this->serveroutput->response[$i]['attributes']) == "job-attributes") + for ($j = 0 ; array_key_exists($j,$this->serveroutput->response[$i]) ; $j++) + if ($this->serveroutput->response[$i][$j]['name'] == "printer-uri") { + $this->printers_uri = array_merge($this->printers_uri,array($this->serveroutput->response[$i][$j]['value'])); + + return; + + } + + $this->printers_uri = array_merge($this->printers_uri,array('')); + + } + // }}} + */ + +// REQUEST BUILDING + + // {{{ _stringCancel () + protected function _stringCancel ($job_uri) { + + if (!isset($this->setup->charset)) + self::setCharset('us-ascii'); + if (!isset($this->setup->datatype)) + self::setBinary(); + if (!isset($this->setup->language)) + self::setLanguage('en_us'); + if (!$this->requesting_user) + self::setUserName(); + if (!isset($this->meta->message)) + $this->meta->message = ''; + + self::_setOperationId(); + + self::_setJobUri($job_uri); + + if (!isset($this->error_generation->request_body_malformed)) + $this->error_generation->request_body_malformed = ""; + + $this->stringjob = chr(0x01) . chr(0x01) // 1.1 | version-number + . chr(0x00) . chr (0x08) // cancel-Job | operation-id + . $this->meta->operation_id // request-id + . $this->error_generation->request_body_malformed + . chr(0x01) // start operation-attributes | operation-attributes-tag + . $this->meta->charset + . $this->meta->language + . $this->meta->job_uri + . $this->meta->username + . $this->meta->message + . chr(0x03); // end-of-attributes | end-of-attributes-tag + + self::_putDebug( sprintf(_("String sent to the server is:\n%s\n"), $this->stringjob)); + return TRUE; + } + // }}} + + +}; + +/* + * Local variables: + * mode: php + * tab-width: 4 + * c-basic-offset: 4 + * End: + */ +?> diff --git a/Moodle/mod/print/README.txt b/Moodle/mod/print/README.txt new file mode 100755 index 0000000..c9d7bf1 --- /dev/null +++ b/Moodle/mod/print/README.txt @@ -0,0 +1,75 @@ +$Id: README.txt,v 1.2.2.2 2009/03/18 14:49:20 mudrd8mz Exp $ + +HOW TO STARTUP WITH A NEW ACTIVITY MODULE +========================================= + +The following steps should get you up and running with +this module template code. + +As you are able to read this file, you have probably managed to get this +source code from either the CVS repository or from the zip archive. Well done! + +Read this README file. + +Make sure you have read this file :-) + +Rename the NEWMODULE folder into a lower case name of your module. Make sure +your name is not used by any standard or contributed modules (see +http://cvs.moodle.org/contrib/plugins/mod/ for the list of currently +contributed modules). + +Edit all the files in this directory and its subdirectories and change all the +instances of string "print" to your new module name (eg "widget"). + +Rename the file lang/en_utf8/print.php to widget.php or whatever your +module name is. + +Place the widget folder into the /mod folder of your development moodle +directory. + +Go to http://localhost/your/moodle/admin/xmldb/ directory. Try to not to visit +the main admin page (Notifications) so the module is not installed yet. If it +gets installed accidentaly, uninstall it from the database via Manage +activities admin page. You will probably uninstall and reinstall the module +quite often during the early stages of the development. + +In XMLDB editor, add all tables, fields and statements needed to implement the +module features. See http://docs.moodle.org/en/Development:Using_XMLDB for +more information. Do not forget to use the [Save] link at the XMLDB main page +so the changes are written into install.xml file. If the link is not active, +the web server process (eg. apache user) does not have permission to write +into mod/widget/db/install.xml file + +Visit the admin Notifications page (admin/index.php). The module tables should +get installed. + +You can go to Modules > Activities in the Site Administration block. You +should find that this print has been added to the list of recognized +modules. + +You may now proceed to run your own code in an attempt to develop for moodle. +Good luck with that. For help with developing code for moodle, visit the +"Activity modules" developers forum in the online course called "Using Moodle" +at http://moodle.org. + + +What to do next +--------------- + +Go through the lib.php, index.php and view.php files. + +You will probably want to add some capabilities regarding your module. Look at +db/access.php. Note that you have to increase the version number defined in +version.php to let Moodle update the capabilities information. + +If you do any change to the database structure (adding a field, changing the +field definition etc.) use XMLDB editor again. Use the PHP code generated by +XMLDB and push it into db/upgrade.php. Save the change into install.xml (for +fresh installations), increase the version number and go to admin/index.php +again. During upgrade, Moodle calls a function in db/upgrade.php to perform +the DB changes. + +Credits for work on this NEWMODULE template +------------------------------------------- +Martin Dougiamas for the original work +Chris B Stones (http://www.welcometochrisworld.com) for revision of the code diff --git a/Moodle/mod/print/db/access.php b/Moodle/mod/print/db/access.php new file mode 100755 index 0000000..7196b71 --- /dev/null +++ b/Moodle/mod/print/db/access.php @@ -0,0 +1,71 @@ +: +// +// component_name should be the same as the directory name of the mod or block. +// +// Core moodle capabilities are defined thus: +// moodle/: +// +// Examples: mod/forum:viewpost +// block/recent_activity:view +// moodle/site:deleteuser +// +// The variable name for the capability definitions array follows the format +// $__capabilities +// +// For the core capabilities, the variable is $moodle_capabilities. + + +$mod_print_capabilities = array( + + 'mod/print:view' => array( + + 'captype' => 'read', + 'contextlevel' => CONTEXT_MODULE, + 'legacy' => array( + 'guest' => CAP_ALLOW, + 'student' => CAP_ALLOW, + 'teacher' => CAP_ALLOW, + 'editingteacher' => CAP_ALLOW, + 'admin' => CAP_ALLOW + ) + ), + + 'mod/print:submit' => array( + + 'captype' => 'write', + 'contextlevel' => CONTEXT_MODULE, + 'legacy' => array( + 'student' => CAP_ALLOW + ) + ), + + 'mod/print:grade' => array( + 'riskbitmask' => RISK_XSS, + + 'captype' => 'write', + 'contextlevel' => CONTEXT_MODULE, + 'legacy' => array( + 'teacher' => CAP_ALLOW, + 'editingteacher' => CAP_ALLOW, + 'admin' => CAP_ALLOW + ) + ) +); + +?> \ No newline at end of file diff --git a/Moodle/mod/print/db/install.xml b/Moodle/mod/print/db/install.xml new file mode 100755 index 0000000..7df1ee3 --- /dev/null +++ b/Moodle/mod/print/db/install.xml @@ -0,0 +1,58 @@ + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + +
+
+ + + + + + + + + +
diff --git a/Moodle/mod/print/db/upgrade.php b/Moodle/mod/print/db/upgrade.php new file mode 100755 index 0000000..632c262 --- /dev/null +++ b/Moodle/mod/print/db/upgrade.php @@ -0,0 +1,134 @@ +setAttributes(XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, null, null, '0', 'id'); + /// Launch add field course + $result = $result && add_field($table, $field); + + /// Define field intro to be added to print + $table = new XMLDBTable('print'); + $field = new XMLDBField('intro'); + $field->setAttributes(XMLDB_TYPE_TEXT, 'medium', null, null, null, null, null, null, 'name'); + /// Launch add field intro + $result = $result && add_field($table, $field); + + /// Define field introformat to be added to print + $table = new XMLDBTable('print'); + $field = new XMLDBField('introformat'); + $field->setAttributes(XMLDB_TYPE_INTEGER, '4', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, null, null, '0', 'intro'); + /// Launch add field introformat + $result = $result && add_field($table, $field); + } + +/// Second example, some hours later, the same day 20070401 +/// two more fields and one index were added (note the increment +/// "01" in the last two digits of the version + if ($result && $oldversion < 2007040101) { + + /// Define field timecreated to be added to print + $table = new XMLDBTable('print'); + $field = new XMLDBField('timecreated'); + $field->setAttributes(XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, null, null, '0', 'introformat'); + /// Launch add field timecreated + $result = $result && add_field($table, $field); + + /// Define field timemodified to be added to print + $table = new XMLDBTable('print'); + $field = new XMLDBField('timemodified'); + $field->setAttributes(XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, null, null, '0', 'timecreated'); + /// Launch add field timemodified + $result = $result && add_field($table, $field); + + /// Define index course (not unique) to be added to print + $table = new XMLDBTable('print'); + $index = new XMLDBIndex('course'); + $index->setAttributes(XMLDB_INDEX_NOTUNIQUE, array('course')); + /// Launch add index course + $result = $result && add_index($table, $index); + } + +/// Third example, the next day, 20070402 (with the trailing 00), some inserts were performed, related with the module + if ($result && $oldversion < 2007040200) { + /// Add some actions to get them properly displayed in the logs + $rec = new stdClass; + $rec->module = 'print'; + $rec->action = 'add'; + $rec->mtable = 'print'; + $rec->filed = 'name'; + /// Insert the add action in log_display + $result = insert_record('log_display', $rec); + /// Now the update action + $rec->action = 'update'; + $result = insert_record('log_display', $rec); + /// Now the view action + $rec->action = 'view'; + $result = insert_record('log_display', $rec); + } + +/// And that's all. Please, examine and understand the 3 example blocks above. Also +/// it's interesting to look how other modules are using this script. Remember that +/// the basic idea is to have "blocks" of code (each one being executed only once, +/// when the module version (version.php) is updated. + +/// Lines above (this included) MUST BE DELETED once you get the first version of +/// yout module working. Each time you need to modify something in the module (DB +/// related, you'll raise the version and add one upgrade block here. + +/// Final return of upgrade result (true/false) to Moodle. Must be +/// always the last line in the script + return $result; +} + +?> diff --git a/Moodle/mod/print/delete.php b/Moodle/mod/print/delete.php new file mode 100755 index 0000000..9636d3c --- /dev/null +++ b/Moodle/mod/print/delete.php @@ -0,0 +1,41 @@ +instance)) { + error("assignment ID was incorrect"); + } + + if (! $course = get_record('course', 'id', $assignment->course)) { + error("Course is misconfigured"); + } + } else { + if (!$assignment = get_record('print', 'id', $a)) { + error("Course module is incorrect"); + } + if (! $course = get_record('course', 'id', $assignment->course)) { + error("Course is misconfigured"); + } + if (! $cm = get_coursemodule_from_instance('print', $assignment->id, $course->id)) { + error("Course Module ID was incorrect"); + } + } + + require_login($course->id, false, $cm); + +/// Load up the required assignment code + $assignmentclass = 'print_base'; + $assignmentinstance = new $assignmentclass($cm->id, $assignment, $cm, $course); + + $assignmentinstance->delete(); // delete something + +?> diff --git a/Moodle/mod/print/http_class.php b/Moodle/mod/print/http_class.php new file mode 100755 index 0000000..f0285af --- /dev/null +++ b/Moodle/mod/print/http_class.php @@ -0,0 +1,629 @@ +errno = $errno; + } + + public function getErrorFormatted() { + + $return = sprintf("[http_class]: %s -- "._(" file %s, line %s"), + $this->getMessage(), + $this->getFile(), + $this->getLine()); + + return $return; + } + + public function getErrno() { + + return $this->errno ; + } + +} + // }}} + +/************************* +* +* class http_class +* +**************************/ + +class http_class { + + // {{{ variables declaration + public $debug; + public $html_debug; + public $timeout = 30; // time waiting for connection, seconds + public $data_timeout = 30; // time waiting for data, milliseconds + public $force_multipart_form_post; + public $username; + public $password; + public $request_headers = array(); + public $request_body = "Not a useful information"; + public $status; + public $window_size = 10000; // chunk size of data + public $with_exceptions = 0; // compatibility mode for old scripts + public $port; + public $host; + + private $default_port = 631; + private $headers; + private $reply_headers = array(); + private $reply_body = array(); + private $connection; + private $arguments; + private $bodystream = array(); + private $last_limit; + private $connected; + private $nc = 1; + private $user_agent = "PRINTIPP/0.81"; + // }}} + + // {{{ constructor + public function __construct() { + true; + } + // }}} + +/********************* +* +* Public functions +* +**********************/ + + // {{{ GetRequestArguments ($url,&$arguments) + public function GetRequestArguments ($url,&$arguments) { + + $this->arguments = array(); + + $arguments["URL"] = $this->arguments["URL"] = $url; + $arguments["RequestMethod"] = $this->arguments["RequestMethod"] = "POST"; + $this->headers["Content-Length"] = 0; + $this->headers["Content-Type"] = "application/octet-stream"; + $this->headers["Host"] = $this->host; + $this->headers["User-Agent"] = $this->user_agent; + //$this->headers["Expect"] = "100-continue"; + } + // }}} + + // {{{ Open ($arguments) + public function Open ($arguments) { + $this->connected = false; + if (!$this->timeout) + $this->timeout = 30; + $url = $arguments["URL"]; + $port = $this->default_port; + + $url = split (':',$url,2); + $transport_type = $url[0]; + $unix = false; + switch($transport_type) { + case 'http': + $transport_type = 'tcp://'; + break; + case 'https': + $transport_type = 'tls://'; + break; + case 'unix': + $transport_type = 'unix://'; + $port = 0; + $unix = true; + break; + default: + $transport_type = 'tcp://'; + break; + } + $url = $url[1]; + if (!$unix) { + $url = split("/",preg_replace("#^/{1,}#",'',$url),2); + $url = $url[0]; + $port = $this->port; + $error = sprintf(_("Cannot resolve url: %s"),$url); + $ip = gethostbyname($url); + $ip = @gethostbyaddr($ip); + if (!$ip) + if ($this->with_exceptions) + throw new httpException($error); + else + { + trigger_error($error,E_USER_WARNING); + return false; + } + if (strstr($url,":")) // we got an ipv6 address + if (!strstr($url,"[")) // it is not escaped + $url = sprintf("[%s]",$url); + } + $this->connection = @fsockopen($transport_type.$url, $port, $errno, $errstr, $this->timeout); + $error = sprintf (_('Unable to connect to "%s%s port %s": %s'), + $transport_type, + $url, + $port, + $errstr); + + if (!$this->connection) + if ($this->with_exceptions) + { + $this->connected = false; + throw new httpException($error,$errno); + } + else + { + trigger_error($error,E_USER_WARNING); + $this->connected = false; + return $error; + } + $this->connected = true; + } + // }}} + + // {{{ SendRequest($arguments) + public function SendRequest($arguments) { + + if (!$this->data_timeout) + $this->data_timeout = 30; + + if(!$result = self::_StreamRequest($arguments)) + return("SendRequest: unknown error"); + + self::_ReadReply(); + + if (!preg_match('#http/1.1 401 unauthorized#',$this->status)) + return; + + + $headers = array_keys ($this->reply_headers); + if (!in_array("www-authenticate",$headers)) + return("SendRequest: need authentication but no mechanism provided"); + + $authtype = split(' ',$this->reply_headers["www-authenticate"]); + $authtype = strtolower($authtype[0]); + + switch ($authtype) { + case 'basic': + $pass = base64_encode($this->user.":".$this->password); + $arguments["Headers"]["Authorization"] = "Basic ".$pass; + break; + case 'digest': + $arguments["Headers"]["Authorization"] = self::_BuildDigest(); + break; + default: + return sprintf(_("http_class: need '%s' authentication mechanism, but have not, sorry"),$authtype[0]); + } + + self::Close(); + self::Open($arguments); + + if(!$result = self::_StreamRequest($arguments)) + return("SendRequest: unknown error"); + + self::_ReadReply(); + + } + // }}} + + // {{{ ReadReplyHeaders (&$headers) + public function ReadReplyHeaders (&$headers) { + if ($this->connected) + $headers = $this->reply_headers; + } + // }}} + + // {{{ ReadReplyBody (&$body,$chunk_size) + public function ReadReplyBody (&$body,$chunk_size) { + $body = substr($this->reply_body,$this->last_limit,$chunk_size); + $this->last_limit += $chunk_size; + } + // }}} + + // {{{ Close () + public function Close () { + if (!$this->connected) return; + fclose ($this->connection); + } + // }}} + +/********************* +* +* Private functions +* +**********************/ + + // {{{ _StreamRequest ($arguments) + private function _StreamRequest ($arguments) { + if (!$this->connected) return; + + $this->status = ""; + $this->reply_headers = array(); + $this->reply_body = ""; + + $this->arguments = $arguments; + + $content_length = 0; + foreach ($this->arguments["BodyStream"] as $argument) { + + list($type,$value) = each($argument); + reset ($argument); + + if ($type == "Data") + $length = strlen($value); + + elseif ($type == "File") + if (is_readable($value)) + $length = filesize($value); + else { + $length = 0; + trigger_error(sprintf(_("%s: file is not readable"),$value),E_USER_WARNING); + } + + else { + $length = 0; + trigger_error(sprintf(_("%s: not a valid argument for content"),$type),E_USER_WARNING); + } + + $content_length += $length; + } + + $this->request_body = sprintf(_("%s Bytes"), $content_length); + $this->headers["Content-Length"] = $content_length; + $this->arguments["Headers"] = array_merge($this->headers,$this->arguments["Headers"]); + + //$read = array($this->connection); + $status = stream_get_meta_data($this->connection); + if (isset($status['unread-bytes']) && $status['unread-bytes']) { + // server talks! + trigger_error(_("http_class: server talk first, quit"),E_USER_WARNING); + return false; + } + + if ($this->arguments["RequestMethod"] != "POST") { + trigger_error (sprintf(_("%s: method not implemented"),$arguments["RequestMethod"]),E_USER_WARNING); + return sprintf(_("%s: method not implemented"),$arguments["RequestMethod"]); + } + + $string = sprintf("POST %s HTTP/1.1\r\n",$this->arguments["RequestURI"]); + $error = fwrite($this->connection,$string); + $this->request_headers[$string] = ''; + + //if(stream_select($read, $write = NULL, $except = NULL, 0) === 1) // server talks! + $status = stream_get_meta_data($this->connection); + if (isset($status['unread-bytes']) && $status['unread-bytes']) + return "server-talk"; + if (!$error) { + trigger_error(_("Error while puts first header"),E_USER_WARNING); + return _("Stream closed while puts first header"); + } + + foreach ($this->arguments["Headers"] as $header => $value) { + + $error = @fwrite($this->connection,sprintf("%s: %s\r\n", $header, $value)); + $this->request_headers[$header] = $value; + //if(stream_select($read, $write = NULL, $except = NULL, 0) === 1) + $status = stream_get_meta_data($this->connection); + if (isset($status['unread-bytes']) && $status['unread-bytes']) + return "server-talk"; + + if (!$error) { + trigger_error(_("Error while puts HTTP headers"),E_USER_WARNING); + return _("Stream closed while puts HTTP headers"); + } + } + + $error = fwrite($this->connection,"\r\n"); + //fflush($this->connection); + + //if($strselect = stream_select($read, $write = NULL, $except = NULL, 0,$this->data_timeout*1000) === 1) + //usleep($this->data_timeout*1000); + $status = stream_get_meta_data($this->connection); + if (isset($status['unread-bytes']) && $status['unread-bytes']) + return "server-talk"; + + if (!$error) { + trigger_error(_("Error while ends HTTP headers"),E_USER_WARNING); + return _("Stream closed while ends HTTP headers"); + } + + foreach ($this->arguments["BodyStream"] as $argument) { + + list($type,$value) = each($argument); + reset ($argument); + + + if ($type == "Data") { + $streamed_length = 0; + while ($streamed_length < strlen($value)) { + //if(stream_select($read, $write = NULL, $except = NULL, 0) === 1) + //usleep($this->data_timeout*1000); + $status = stream_get_meta_data($this->connection); + if (isset($status['unread-bytes']) && $status['unread-bytes']) + return "server-talk"; + + // not very clean... + $error = @fwrite($this->connection,substr($value,$streamed_length,$this->window_size)); + if (!$error) + return "error-while-push-data"; + $streamed_length += $this->window_size; + } + } + + if (!$error) + return _("error-while-push-data"); + + elseif ($type == "File") { + if (is_readable($value)) { + $file = fopen($value,'rb'); + while(!feof($file)) { + + if(gettype($block = @fread($file,$this->window_size)) != "string") { + trigger_error(_("cannot read file to upload"),E_USER_WARNING); + return _("cannot read file to upload"); + } + + //if(stream_select($read, $write = NULL, $except = NULL, 0) === 1) + $status = stream_get_meta_data($this->connection); + if (isset($status['unread-bytes']) && $status['unread-bytes']) + return "server-talks"; + + // not very clean... + $error = @fwrite($this->connection,$block); + if (!$error) + return "error-while-push-data"; + + } + } + } + + //if(stream_select($read, $write = NULL, $except = NULL, 0) === 1) + $status = stream_get_meta_data($this->connection); + if (isset($status['unread-bytes']) && $status['unread-bytes']) + return "server-talks"; + + } + + return true; + } + // }}} + + // {{{ _ReadReply () + private function _ReadReply () { + + if (!$this->connected) return; + + $this->reply_headers = array(); + $this->reply_body = ""; + + + + $line = "1\r\n"; + $headers = ""; + $body = ""; + while (!feof($this->connection)) { + $line = fgets($this->connection,1024); + if (strlen($line) <= 2) + break; + $headers .= $line; + } + $chunk = true; + + $headers = preg_split('#\r\n#',$headers); + + $this->status = strtolower($headers[0]); + + foreach($headers as $header) { + if (!preg_match('#www-authenticate: #i',$header)) + $header = strtolower($header); + + $header = preg_split("#: #",$header); + $header[0] = strtolower($header[0]); + + $this->reply_headers["{$header[0]}"] = array_key_exists(1,$header) ? $header[1] : ""; + } + unset ($this->reply_headers['']); + + //giving 3 chances to complete reading + $read = array($this->connection); + for ($i = 0 ; $i < 2 ; $i++) { + if (self::_ReadStream() === "completed") + break; + //$strselect = stream_select($read, $write = NULL, $except = NULL, 0,$this->data_timeout*1000); + //if (!$strselect) + //usleep($this->data_timeout*1000); + $status = stream_get_meta_data ($this->connection); + if ($status["unread_bytes"] == 0) + break; + } + + return true; + } + // }}} + + // {{{ _ReadStream () + private function _ReadStream () { + + $content_length = 0; + if (array_key_exists("content-length",$this->reply_headers)); + $content_length = $this->reply_headers["content-length"]; + + stream_set_blocking ($this->connection, 0 ); + usleep($this->data_timeout * 1000); + $total = 0; + $chunk = true; + while (true) { + if ($content_length) + if (strlen($this->reply_body) >= $content_length) + return "completed"; + else + if (!$chunk) + break; + usleep (1000); + $chunk = @fread($this->connection,$this->window_size); + $this->reply_body .= $chunk; + + $status = stream_get_meta_data ($this->connection); + if ($status["unread_bytes"] == 0) + break; + } + stream_set_blocking ($this->connection, 1 ); + return true; + } + // }}} + + // {{{ _BuildDigest () + private function _BuildDigest () { + + $auth = $this->reply_headers["www-authenticate"]; + + list($head, $auth) = split(" ",$auth,2); + + $auth=split(", ",$auth); + foreach ($auth as $sheme) { + list($sheme,$value) = split('=',$sheme); + $fields[$sheme] = trim(trim($value),'"'); + } + + $nc = sprintf('%x',$this->nc); + $prepend = ""; + while ((strlen($nc) + strlen($prepend)) < 8) + $prepend .= "0"; + $nc=$prepend.$nc; + + $cnonce = "printipp"; + + $username = $this->user; + $password = $this->password; + + $A1 = $username.":".$fields["realm"].":".$password; + + if (array_key_exists("algorithm",$fields)) { + $algorithm = strtolower($fields["algorithm"]); + switch ($algorithm) { + case "md5": + break; + case "md5-sess": + $A1 = $username.":".$fields["realm"].":".$password.":".$fields['nonce'].":".$cnonce; + break; + case "token": + trigger_error("http_class: digest Authorization: algorithm 'token' not implemented", E_USER_WARNING); + return false; + break; + } + + } + + $A2 = "POST:".$this->arguments["RequestURI"]; + + + if (array_key_exists("qop",$fields)) { + $qop = strtolower($fields["qop"]); + $qop = split(" ",$qop); + if (in_array("auth",$qop)) + $qop = "auth"; + else { + trigger_error("http_class: digest Authorization: qop others than 'auth' not implemented", E_USER_WARNING); + return false; + } + } + + //echo $A1,":",$fields["nonce"],":",$A2,"
"; + $response = md5(md5($A1).":". $fields["nonce"].":" .md5($A2)); + + if (isset($qop) && ($qop == "auth")) + { + $response = md5(md5($A1).":".$fields["nonce"].":".$nc.":".$cnonce.":".$qop.":".$A2); + } + + $auth_scheme = sprintf('Digest username="%s", realm="%s", nonce="%s", uri="%s", response="%s"', + $username, + $fields["realm"], + $fields['nonce'], + $this->arguments["RequestURI"], + $response + ); + //echo $auth_scheme,"
"; + if (isset($algorithm)) + $auth_scheme .= sprintf(', algorithm="%s"',$algorithm); + + if (isset($qop)) + $auth_scheme .= sprintf(', cnonce="%s"',$cnonce); + + if(array_key_exists("opaque",$fields)) + $auth_scheme .= sprintf(', opaque="%s"',$fields['opaque']); + + if (isset($qop)) + $auth_scheme .= sprintf(', qop="%s"',$qop); + + $auth_scheme .= sprintf(', nc=%s',$nc); + + $this->nc++; + + return $auth_scheme; + } + // }}} + +}; + + +/* + * Local variables: + * mode: php + * tab-width: 4 + * c-basic-offset: 4 + * End: + */ +?> diff --git a/Moodle/mod/print/icon.gif b/Moodle/mod/print/icon.gif new file mode 100755 index 0000000..550df5d --- /dev/null +++ b/Moodle/mod/print/icon.gif Binary files differ diff --git a/Moodle/mod/print/index.php b/Moodle/mod/print/index.php new file mode 100755 index 0000000..f69e372 --- /dev/null +++ b/Moodle/mod/print/index.php @@ -0,0 +1,89 @@ + + * @version $Id: index.php,v 1.7.2.2 2009/03/31 13:07:21 mudrd8mz Exp $ + * @package mod/print + */ + +/// Replace print with the name of your module and remove this line + +require_once(dirname(dirname(dirname(__FILE__))).'/config.php'); +require_once(dirname(__FILE__).'/lib.php'); + +$id = required_param('id', PARAM_INT); // course + +if (! $course = get_record('course', 'id', $id)) { + error('Course ID is incorrect'); +} + +require_course_login($course); + +add_to_log($course->id, 'print', 'view all', "index.php?id=$course->id", ''); + + +/// Get all required stringsprint + +$strprints = get_string('modulenameplural', 'print'); +$strprint = get_string('modulename', 'print'); + + +/// Print the header + +$navlinks = array(); +$navlinks[] = array('name' => $strprints, 'link' => '', 'type' => 'activity'); +$navigation = build_navigation($navlinks); + +print_header_simple($strprints, '', $navigation, '', '', true, '', navmenu($course)); + +/// Get all the appropriate data + +if (! $prints = get_all_instances_in_course('print', $course)) { + notice('There are no instances of print', "../../course/view.php?id=$course->id"); + die; +} + +/// Print the list of instances (your module will probably extend this) + +$timenow = time(); +$strname = get_string('name'); +$strweek = get_string('week'); +$strtopic = get_string('topic'); + +if ($course->format == 'weeks') { + $table->head = array ($strweek, $strname); + $table->align = array ('center', 'left'); +} else if ($course->format == 'topics') { + $table->head = array ($strtopic, $strname); + $table->align = array ('center', 'left', 'left', 'left'); +} else { + $table->head = array ($strname); + $table->align = array ('left', 'left', 'left'); +} + +foreach ($prints as $print) { + if (!$print->visible) { + //Show dimmed if the mod is hidden + $link = "coursemodule\">$print->name"; + } else { + //Show normal if the mod is visible + $link = "coursemodule\">$print->name"; + } + + if ($course->format == 'weeks' or $course->format == 'topics') { + $table->data[] = array ($print->section, $link); + } else { + $table->data[] = array ($link); + } +} + +print_heading($strprints); +print_table($table); + +/// Finish the page + +print_footer($course); + +?> diff --git a/Moodle/mod/print/lang/en_utf8/help/newmodule/index.html b/Moodle/mod/print/lang/en_utf8/help/newmodule/index.html new file mode 100755 index 0000000..5927327 --- /dev/null +++ b/Moodle/mod/print/lang/en_utf8/help/newmodule/index.html @@ -0,0 +1,6 @@ +

print

+

Delete me! This file contains a list of all the help files available for the module. Don't + forget to add each individual help file to the html list below. Delete me!

+ diff --git a/Moodle/mod/print/lang/en_utf8/help/newmodule/mods.html b/Moodle/mod/print/lang/en_utf8/help/newmodule/mods.html new file mode 100755 index 0000000..f018f4c --- /dev/null +++ b/Moodle/mod/print/lang/en_utf8/help/newmodule/mods.html @@ -0,0 +1,18 @@ +

 print

+
+

This file contains the main description of the print module. Usually, it's used to +explain the main features of the activity, with a natural language. Also, the overall +process of the activity is detailed here with its pedagogical foundation.

+ +

From a developer perspective, this "help" directory will contain simple html files +like this that you will be able to link from print code when any sort of +explanation is necessary (it's easier to add those links automatically, both from +the formslib stuff (see mod_form.php) and from everywhere else (see the helpbutton() +function).

+ +

Also, don't forget to add one link to this help file from the print/help "index.html" +file, it will allow Moodle to show all the existing help files related to the module when the +complete list of available help files is requested.

+ +

Please, replace me with the real information about the print!

+
diff --git a/Moodle/mod/print/lang/en_utf8/newmodule.php b/Moodle/mod/print/lang/en_utf8/newmodule.php new file mode 100755 index 0000000..13026b3 --- /dev/null +++ b/Moodle/mod/print/lang/en_utf8/newmodule.php @@ -0,0 +1,12 @@ + diff --git a/Moodle/mod/print/lib.php b/Moodle/mod/print/lib.php new file mode 100755 index 0000000..6bcc38c --- /dev/null +++ b/Moodle/mod/print/lib.php @@ -0,0 +1,1195 @@ +cm = $cm; + } else if (! $this->cm = get_coursemodule_from_id('print', $cmid)) { + error('Course Module ID was incorrect'); + } + $this->context = get_context_instance(CONTEXT_MODULE, $this->cm->id); + + if ($course) { + $this->course = $course; + } else if ($this->cm->course == $COURSE->id) { + $this->course = $COURSE; + } else if (! $this->course = get_record('course', 'id', $this->cm->course)) { + error('Course is misconfigured'); + } + + if ($printconfig) { + $this->printconfig = $printconfig; + } else if (! $this->printconfig = get_record('print', 'id', $this->cm->instance)) { + error('print ID was incorrect'); + } + + #$this->submissions = $this->check_database("print_submissions"); + $this->printconfig->cmidnumber = $this->cm->id; // compatibility with modedit assignment obj + $this->printconfig->courseid = $this->course->id; // compatibility with modedit assignment obj + $this->printconfig->maxbytes = 2097152; +} +function check_database($table) { + global $CFG,$USER; + $sql = "SELECT * + FROM {$CFG->prefix}$table + WHERE userid = '$USER->id' + AND assignment = '{$this->printconfig->id}'"; + + return $sql; + +} + +function view1() { + global $USER; + + require_capability('mod/print:view', $this->context); + + add_to_log($this->course->id, 'print', 'view', "view.php?id={$this->cm->id}", $this->printconfig->id, $this->cm->id); + + $this->view_header(); + + + if (has_capability('mod/print:submit', $this->context)) { + + if ($this->submissions = get_records_sql($this->check_database("print_submissions"))) { + + + } else { + $substring = "No Submissions yet"; + print_simple_box(get_string('nofilesyet', 'assignment'), 'center'); + } + + + $filecount = $this->count_user_files($USER->id); + $submission = $this->get_submissions1($USER->id); + + # $this->view_feedback(); + + print_heading(get_string('submissiondraft', 'assignment'), '', 3); + + + if ($filecount and $submission) { + print_simple_box($this->print_user_files($USER->id, true), 'center'); + } else { + print_simple_box(get_string('nofilesyet', 'assignment'), 'center'); + } + + + $this->view_upload_form(); + + + } + } + function view_header($subpage='') { + + global $CFG; + + + if ($subpage) { + $navigation = build_navigation($subpage, $this->cm); + } else { + $navigation = build_navigation('', $this->cm); + } + + print_header('Print Uploads', $this->course->fullname, $navigation, '', '', + true, update_module_button($this->cm->id, $this->course->id, ''), + navmenu($this->course, $this->cm)); + + groups_print_activity_menu($this->cm, 'view.php?id=' . $this->cm->id); + + echo ''; + echo '
'; + } + + function submissions($mode) { + ///The main switch is changed to facilitate + ///1) Batch fast grading + ///2) Skip to the next one on the popup + ///3) Save and Skip to the next one on the popup + + //make user global so we can use the id + global $USER; + + + switch ($mode) { + case 'single': // We are in a popup window displaying submission + $this->display_submission(); + break; + + case 'all': // Main window, display everything + $this->display_submissions(); + break; + + + foreach ($_POST[$col] as $id => $unusedvalue){ + + $id = (int)$id; //clean parameter name + + $this->process_outcomes($id); + + if (!$submission = $this->get_submission($id)) { + $submission = $this->prepare_new_submission($id); + $newsubmission = true; + } else { + $newsubmission = false; + } + unset($submission->data1); // Don't need to update this. + unset($submission->data2); // Don't need to update this. + + //for fast grade, we need to check if any changes take place + $updatedb = false; + + if ($commenting) { + $commentvalue = trim($_POST['submissioncomment'][$id]); + $updatedb = $updatedb || ($submission->submissioncomment != stripslashes($commentvalue)); + $submission->submissioncomment = $commentvalue; + } else { + unset($submission->submissioncomment); // Don't need to update this. + } + + $submission->teacher = $USER->id; + if ($updatedb) { + $submission->mailed = (int)(!$mailinfo); + } + + $submission->timemarked = time(); + + //if it is not an update, we don't change the last modified time etc. + //this will also not write into database if no submissioncomment and grade is entered. + + if ($updatedb){ + if ($newsubmission) { + if (!isset($submission->submissioncomment)) { + $submission->submissioncomment = ''; + } + if (!$sid = insert_record('print_submissions', $submission)) { + return false; + } + $submission->id = $sid; + } else { + if (!update_record('print_submissions', $submission)) { + return false; + } + } + + // triger grade event + $this->update_grade($submission); + + //add to log only if updating + add_to_log($this->course->id, 'print', 'update grades', + 'submissions.php?id='.$this->printconfig->id.'&user='.$submission->userid, + $submission->userid, $this->cm->id); + } + + } + + $message = notify(get_string('changessaved'), 'notifysuccess', 'center', true); + + $this->display_submissions($message); + break; + + + case 'next': + /// We are currently in pop up, but we want to skip to next one without saving. + /// This turns out to be similar to a single case + /// The URL used is for the next submission. + + $this->display_submission(); + break; + + case 'saveandnext': + ///We are in pop up. save the current one and go to the next one. + //first we save the current changes + if ($submission = $this->process_feedback()) { + //print_heading(get_string('changessaved')); + $extra_javascript = $this->update_main_listing($submission); + } + + //then we display the next submission + $this->display_submission($extra_javascript); + break; + + default: + echo "something seriously is wrong!!"; + break; + } + +} + function display_submissions($message='') { + global $CFG, $db, $USER; + require_once($CFG->libdir.'/gradelib.php'); + + /* first we check to see if the form has just been submitted + * to request user_preference updates + */ + + if (isset($_POST['updatepref'])){ + $perpage = optional_param('perpage', 10, PARAM_INT); + $perpage = ($perpage <= 0) ? 10 : $perpage ; + set_user_preference('assignment_perpage', $perpage); + set_user_preference('assignment_quickgrade', optional_param('quickgrade', 0, PARAM_BOOL)); + } + + /* next we get perpage and quickgrade (allow quick grade) params + * from database + */ + $perpage = get_user_preferences('assignment_perpage', 10); + + + if (!empty($CFG->enableoutcomes) and !empty($grading_info->outcomes)) { + $uses_outcomes = true; + } else { + $uses_outcomes = false; + } + + $page = optional_param('page', 0, PARAM_INT); + $strsaveallfeedback = get_string('saveallfeedback', 'assignment'); + + /// Some shortcuts to make the code read better + + $course = $this->course; + $assignment = $this->printconfig; + $cm = $this->cm; + + $tabindex = 1; //tabindex for quick grading tabbing; Not working for dropdowns yet + add_to_log($course->id, 'print', 'view submission', 'submissions.php?id='.$this->cm->id, $this->printconfig->id, $this->cm->id); + $navigation = build_navigation('submissions', $this->cm); + print_header_simple(format_string($this->printconfig->name,true), "", $navigation, + '', '', true, update_module_button($cm->id, $course->id, 'print'), navmenu($course, $cm)); + + $course_context = get_context_instance(CONTEXT_COURSE, $course->id); + + + if (!empty($message)) { + echo $message; // display messages here if any + } + + $context = get_context_instance(CONTEXT_MODULE, $cm->id); + + /// Check to see if groups are being used in this assignment + + /// find out current groups mode + $groupmode = groups_get_activity_groupmode($cm); + $currentgroup = groups_get_activity_group($cm, true); + groups_print_activity_menu($cm, 'submissions.php?id=' . $this->cm->id); + + /// Get all ppl that are allowed to submit assignments + if ($users = get_users_by_capability($context, 'mod/print:submit', 'u.id', '', '', '', $currentgroup, '', false)) { + $users = array_keys($users); + } + + // if groupmembersonly used, remove users who are not in any group + if ($users and !empty($CFG->enablegroupings) and $cm->groupmembersonly) { + if ($groupingusers = groups_get_grouping_members($cm->groupingid, 'u.id', 'u.id')) { + $users = array_intersect($users, array_keys($groupingusers)); + } + } + + $tablecolumns = array('picture', 'fullname', 'status', 'submissions'); + + + $tableheaders = array('', + get_string('fullname'), + get_string('status'), + 'submissions'); + + require_once($CFG->libdir.'/tablelib.php'); + $table = new flexible_table('mod-print-submissions'); + + $table->define_columns($tablecolumns); + $table->define_headers($tableheaders); + $table->define_baseurl($CFG->wwwroot.'/mod/print/submissions.php?id='.$this->cm->id.'&currentgroup='.$currentgroup); + + $table->sortable(true, 'lastname');//sorted by lastname by default + $table->collapsible(true); + $table->initialbars(true); + + $table->column_suppress('picture'); + $table->column_suppress('fullname'); + + $table->column_class('picture', 'picture'); + $table->column_class('fullname', 'fullname'); + $table->column_class('status', 'status'); + $table->column_class('submissions','submissions'); + + $table->set_attribute('cellspacing', '0'); + $table->set_attribute('id', 'attempts'); + $table->set_attribute('class', 'submissions'); + $table->set_attribute('width', '100%'); + $table->set_attribute('align', 'center'); + + $table->no_sorting('outcome'); + + // Start working -- this is necessary as soon as the niceties are over + $table->setup(); + + if (empty($users)) { + print_heading(get_string('nosubmitusers','assignment')); + return true; + } + + /// Construct the SQL + + if ($where = $table->get_sql_where()) { + $where .= ' AND '; + } + + if ($sort = $table->get_sql_sort()) { + $sort = ' ORDER BY '.$sort; + } + + $select = 'SELECT u.id, u.firstname, u.lastname, u.picture, u.imagealt, + s.id AS submissionid, + COALESCE(SIGN(SIGN(s.timemarked) + SIGN(s.timemarked - s.timemodified)), 0) AS status '; + $sql = 'FROM '.$CFG->prefix.'user u '. + 'LEFT JOIN '.$CFG->prefix.'print_submissions s ON u.id = s.userid + AND s.assignment = '.$this->printconfig->id.' '. + 'WHERE '.$where.'u.id IN ('.implode(',',$users).') '; + + $table->pagesize($perpage, count($users)); + + ///offset used to calculate index of student in that particular query, needed for the pop up to know who's next + $offset = $page * $perpage; + + $strupdate = get_string('update'); + $strgrade = get_string('grade'); + #$grademenu = make_grades_menu($this->printconfig->grade); + + if (($ausers = get_records_sql($select.$sql.$sort, $table->get_page_start(), $table->get_page_size())) !== false) { + foreach ($ausers as $auser) { + + /// Calculate user status + $picture = print_user_picture($auser, $course->id, $auser->picture, false, true); + + + if (empty($auser->status)) { /// Confirm we have exclusively 0 or 1 + $auser->status = 0; + } else { + $auser->status = 1; + } + + $buttontext = ($auser->status == 1) ? $strupdate : $strgrade; + + ///No more buttons, we use popups ;-). + $popup_url = '/mod/print/submissions.php?id='.$this->cm->id + . '&userid='.$auser->id.'&mode=single'.'&offset='.$offset++; + $button = link_to_popup_window ($popup_url, 'grade'.$auser->id, $buttontext, 600, 780, + $buttontext, 'none', true, 'button'.$auser->id); + + $status = '
'.$button.'
'; + $url = $this->print_user_files($auser->id,true,true); + $submissions = '
'.$url.'
'; + + $userlink = '' . fullname($auser) . ''; + $row = array($picture, $userlink, $status, $submissions); + if ($uses_outcomes) { + $row[] = $outcomes; + } + + $table->add_data($row); + } + } + + + /// Print quickgrade form around the table + echo '
'; + echo '
'; + echo ''; + echo ''; + echo ''; + echo '
'; + + $table->print_html(); /// Print the whole table + + $lastmailinfo = get_user_preferences('assignment_mailinfo', 1) ? 'checked="checked"' : ''; + echo '
'; + echo '
'; + echo ''; + echo ''; + echo ''; + helpbutton('emailnotification', get_string('enableemailnotification', 'assignment'), 'assignment').'

'; + echo '
'; + echo '
'; + echo ''; + echo '
'; + /// End of fast grading form + + /// Mini form for setting user preference + echo '
'; + echo '
'; + echo ''; + echo ''; + echo ''; + echo ''; + echo ''; + echo ''; + echo '
'; + echo ''; + echo ''; + echo ''; + helpbutton('pagesize', get_string('pagesize','assignment'), 'assignment'); + echo '
'; + echo ''; + echo '
'; + echo ''; + echo '
'; + echo '
'; + ///End of mini form +# print_footer($this->course); + } + + + + function printit($file) { + printit_real($file); + } + + + function submittedlink($allgroups=false) { + global $USER; + + $submitted = ''; + + $context = get_context_instance(CONTEXT_MODULE,$this->cm->id); + if ($allgroups and has_capability('moodle/site:accessallgroups', $context)) { + $group = 0; + } else { + $group = groups_get_activity_group($this->cm); + } + if (has_capability('moodle/site:accessallgroups', $context)) { + if ($count = $this->count_real_submissions($group)) { + $submitted = ''. + get_string('viewsubmissions', 'assignment', $count).''; + } else { + $submitted = ''. + get_string('noattempts', 'assignment').''; + } + } else { + $submitted = ''; + } + return $submitted; + } + function count_real_submissions($groupid=0) { + return print_count_real_submissions($this->cm, $groupid); + } + + function print_user_files($userid=0, $return=false, $url=false) { + global $CFG, $USER; + + $mode = optional_param('mode', '', PARAM_ALPHA); + $offset = optional_param('offset', 0, PARAM_INT); + + if (!$userid) { + if (!isloggedin()) { + return ''; + } + $userid = $USER->id; + } + $filearea = $this->file_area_name($userid); + + $output = ''; + + if ($submissions = $this->get_submissions1($userid)) { + foreach ($submissions as $submission) { + $candelete = $this->can_delete_files($submission); + } + } + $strdelete = get_string('delete'); + + $output .= ''.get_string('draft', 'assignment').':
'; + + + if ($basedir = $this->file_area($userid)) { + if ($files = get_directory_list($basedir, 'responses')) { + require_once($CFG->libdir.'/filelib.php'); + foreach ($files as $key => $file) { + + $icon = mimeinfo('icon', $file); + $ffurl = get_file_url("$filearea/$file"); + if(!$url) { + $output .= ''.$icon.''.$file.''; + } + if ($url){ + $path = $basedir.'/'.$file; + $output .= ''.$icon.''.$file.''. + '
'. + ''. + ''. + '
'; + $sql = "SELECT userid + FROM {$CFG->prefix}print_submissions + WHERE filepath = '$path' + AND assignment = '{$this->printconfig->id}'"; + $submission = get_record_sql($sql); + $candelete = true; + } + if ($candelete) { + $delurl = "$CFG->wwwroot/mod/print/delete.php?id={$this->cm->id}&file=$file&userid={$submission->userid}&mode=$mode&offset=$offset"; + + $output .= ' ' + .' '; + } + + $output .= '
'; + } + } + } + + + $output = '
'.$output.'
'; + + if ($return) { + return $output; + } + echo $output; + +} + function print_get_path($userid) { + global $CFG; + $sql = "SELECT filepath + FROM {$CFG->prefix}print_submissions + WHERE userid = '$userid' + AND assignment = '{$this->printconfig->id}'"; + $records = get_records_sql($sql); + + return $records; + + } + + function delete() { + $action = optional_param('action', '', PARAM_ALPHA); + + switch ($action) { + case 'response': + $this->delete_responsefile(); + break; + default: + $this->delete_file(); + } + die; + } + function delete_file() { + global $CFG; + + $file = required_param('file', PARAM_FILE); + $userid = required_param('userid', PARAM_INT); + $confirm = optional_param('confirm', 0, PARAM_BOOL); + $mode = optional_param('mode', '', PARAM_ALPHA); + $offset = optional_param('offset', 0, PARAM_INT); + + require_login($this->course->id, false, $this->cm); + + if (empty($mode)) { + $urlreturn = 'view.php'; + $optionsreturn = array('id'=>$this->cm->id); + $returnurl = 'view.php?id='.$this->cm->id; + } else { + $urlreturn = 'submissions.php'; + $optionsreturn = array('id'=>$this->cm->id, 'offset'=>$offset, 'mode'=>$mode, 'userid'=>$userid); + $returnurl = "submissions.php?id={$this->cm->id}&offset=$offset&mode=$mode&userid=$userid"; + } + + + $dir = $this->file_area_name($userid); + + if (!data_submitted('nomatch') or !$confirm) { + $optionsyes = array ('id'=>$this->cm->id, 'file'=>$file, 'userid'=>$userid, 'confirm'=>1, 'sesskey'=>sesskey(), 'mode'=>$mode, 'offset'=>$offset); + if (empty($mode)) { + #$this->view_header(get_string('delete')); + } else { + print_header(get_string('delete')); + } + print_heading(get_string('delete')); + notice_yesno(get_string('confirmdeletefile', 'assignment', $file), 'delete.php', $urlreturn, $optionsyes, $optionsreturn, 'post', 'get'); + if (empty($mode)) { + #$this->view_footer(); + } else { + print_footer('none'); + } + die; + } + + $filepath = $CFG->dataroot.'/'.$dir.'/'.$file; + if (file_exists($filepath)) { + if (@unlink($filepath)) { + $sql = "DELETE + FROM {$CFG->prefix}print_submissions + WHERE filepath = '$filepath' + AND assignment = '{$this->printconfig->id}'"; + get_records_sql($sql); + redirect($returnurl); + } + } + + // print delete error + if (empty($mode)) { + #$this->view_header(get_string('delete')); + } else { + #print_header(get_string('delete')); + } + notify(get_string('deletefilefailed', 'assignment')); + print_continue($returnurl); + if (empty($mode)) { + # $this->view_footer(); + } else { + #print_footer('none'); + } + die; + } + + function can_delete_files($submission) { + global $USER; + + + if (has_capability('mod/print:submit', $this->context) + and $USER->id == $submission->userid) { // no deleting after final submission + return true; + } else { + return false; + } + } + function upload() { + $action = required_param('action', PARAM_ALPHA); + + $this->upload_file(); + } + + function count_user_files($userid) { + global $CFG; + + $filearea = $this->file_area_name($userid); + + if ( is_dir($CFG->dataroot.'/'.$filearea) && $basedir = $this->file_area($userid)) { + if ($files = get_directory_list($basedir)) { + return count($files); + } + } + return 0; + } + function setup_elements(&$mform) { + global $CFG, $COURSE; + + $ynoptions = array( 0 => get_string('no'), 1 => get_string('yes')); + + $choices = get_max_upload_sizes($CFG->print_maxbytes, 0); + $choices[0] = get_string('courseuploadlimit') . ' ('.display_size($CFG->print_maxbytes).')'; + $mform->addElement('select', 'maxbytes', get_string('maximumsize', 'assignment'), $choices); + $mform->setDefault('maxbytes', $CFG->print_maxbytes); + + $options = array(); + for($i = 1; $i <= 20; $i++) { + $options[$i] = $i; + } + $mform->addElement('select', 'var1', get_string("allowmaxfiles", "assignment"), $options); + $mform->setHelpButton('var1', array('allowmaxfiles', get_string('allowmaxfiles', 'assignment'), 'assignment')); + $mform->setDefault('var1', 3); + + + + } + + function view_upload_form() { + global $CFG, $USER; + + if(!$this->submissions = get_records_sql($this->check_database("print_submissions"))) { + $this->submission = $this->submissions[1]; + } + $struploadafile = get_string('uploadafile'); + $maxbytes = $this->printconfig->maxbytes == 0 ? $this->course->maxbytes : $this->printconfig->maxbytes; + $strmaxsize = get_string('maxsize', '', display_size($maxbytes)); + + + if ($this->can_upload_file($this->submission)) { + echo '
'; + echo '
'; + echo '
'; + echo "

$struploadafile ($strmaxsize)

"; + echo ''; + echo ''; + require_once($CFG->libdir.'/uploadlib.php'); + upload_print_form_fragment(1,array('newfile'),null,false,null,0,$this->printconfig->maxbytes,false); + echo ''; + echo '
'; + echo '
'; + echo '
'; + echo '
'; + } + + } + function upload_file() { + global $CFG, $USER; + + $mode = optional_param('mode', '', PARAM_ALPHA); + $offset = optional_param('offset', 0, PARAM_INT); + + $returnurl = 'view.php?id='.$this->cm->id; + + $filecount = $this->count_user_files($USER->id); + $submission = $this->get_submission($USER->id); + + if (!$this->can_upload_file($submission)) { + $this->view_header(get_string('upload')); + notify(get_string('uploaderror', 'assignment')); + print_continue($returnurl); + # $this->view_footer(); + die; + } + + $dir = $this->file_area_name($USER->id); + check_dir_exists($CFG->dataroot.'/'.$dir, true, true); // better to create now so that student submissions do not block it later + + require_once($CFG->dirroot.'/lib/uploadlib.php'); + $um = new upload_manager('newfile',false,true,$this->course,false,$this->printconfig->maxbytes,true); + + if ($um->process_file_uploads($dir)) { + $updated = new object(); + $updated->assignment = $this->printconfig->id; + $updated->id = $submission->id; + $updated->timemodified = time(); + $updated->filepath = $um->get_new_filepath(); + $updated->userid = $USER->id; + + if (insert_record('print_submissions', $updated)) { + add_to_log($this->course->id, 'print', 'upload', + 'view.php?a='.$this->printconfig->id, $this->printconfig->id, $this->cm->id); + $submission = $this->get_submission($USER->id); + } else { + $new_filename = $um->get_new_filename(); + $this->view_header(get_string('upload')); + notify(get_string('uploadnotregistered', 'assignment', $new_filename)); + print_continue($returnurl); + # $this->view_footer(); + die; + } + redirect('view.php?id='.$this->cm->id); + } + $this->view_header(get_string('upload')); + notify(get_string('uploaderror', 'assignment')); + echo $um->get_errors(); + print_continue($returnurl); + #$this->view_footer(); + die; + } + + function upload_xmlrpc($filepath, $userid, $title, $id) { + $updated = new object(); + $updated->timemodified = time(); + $updated->filepath = $filepath; + $updated->userid = $userid; + $updated->assignment = $id; + insert_record('print_submissions', $updated); + return 1; + } + + function get_submissions1($userid=0, $createnew=false, $teachermodified=false) { + global $USER; + + if (empty($userid)) { + $userid = $USER->id; + } + + $submission = get_records('print_submissions', 'userid', $userid); + #print var_dump($submission); + if ($submission || !$createnew) { + return $submission; + } + $newsubmission = $this->prepare_new_submission($userid, $teachermodified); + if (!insert_record("print_submissions", $newsubmission)) { + error("Could not insert a new empty submission"); + } + + return get_record('print_submissions', 'assignment', $this->printconfig->id, 'userid', $userid); + } + + function get_submission($userid=0, $createnew=false, $teachermodified=false) { + global $USER; + + if (empty($userid)) { + $userid = $USER->id; + } + + $submission = get_record('print_submissions', 'userid', $userid); + #print var_dump($submission); + if ($submission || !$createnew) { + return $submission; + } + $newsubmission = $this->prepare_new_submission($userid, $teachermodified); + if (!insert_record("print_submissions", $newsubmission)) { + error("Could not insert a new empty submission"); + } + + return get_record('print_submissions', 'assignment', $this->printconfig->id, 'userid', $userid); + } + + function prepare_new_submission($userid, $teachermodified=false) { + $submission = new Object; + $submission->assignment = $this->printconfig->id; + $submission->userid = $userid; + //$submission->timecreated = time(); + $submission->timecreated = ''; + // teachers should not be modifying modified date, except offline assignments + if ($teachermodified) { + $submission->timemodified = 0; + } else { + $submission->timemodified = $submission->timecreated; + } + $submission->numfiles = 0; + $submission->data1 = ''; + $submission->data2 = ''; + $submission->grade = -1; + $submission->submissioncomment = ''; + $submission->format = 0; + $submission->teacher = 0; + $submission->timemarked = 0; + $submission->mailed = 0; + return $submission; + } + function file_area_name($userid) { + global $CFG; + + return $this->course->id.'/'.$CFG->moddata.'/print/'.$this->printconfig->id.'/'.$userid; + } + + function file_area($userid) { + return make_upload_directory( $this->file_area_name($userid) ); + } + + + function can_upload_file($submission) { + global $USER; + + if (has_capability('mod/print:submit', $this->context) // can submit + // assignment not closed yet + and (empty($submission) or $submission->userid == $USER->id)) { // no uploading after final submission + return true; + } else { + return false; + } + } + + + function get_submissions($sort='', $dir='DESC') { + return print_get_all_submissions($this->printconfig, $sort, $dir); + } +} + +function print_count_real_submissions($cm, $groupid=0) { + global $CFG; + + $context = get_context_instance(CONTEXT_MODULE, $cm->id); + + // this is all the users with this capability set, in this context or higher + if ($users = get_users_by_capability($context, 'mod/print:submit', 'u.id', '', '', '', $groupid, '', false)) { + $users = array_keys($users); + } + + // if groupmembersonly used, remove users who are not in any group + if ($users and !empty($CFG->enablegroupings) and $cm->groupmembersonly) { + if ($groupingusers = groups_get_grouping_members($cm->groupingid, 'u.id', 'u.id')) { + $users = array_intersect($users, array_keys($groupingusers)); + } + } + + if (empty($users)) { + return 0; + } + + $userlists = implode(',', $users); + + return count_records_sql("SELECT COUNT('x') + FROM {$CFG->prefix}print_submissions + WHERE assignment = $cm->instance AND + timemodified > 0 AND + userid IN ($userlists)"); +} + + +function print_get_all_submissions($assignment, $sort="", $dir="DESC") { +/// Return all assignment submissions by ENROLLED students (even empty) + global $CFG; + + if ($sort == "lastname" or $sort == "firstname") { + $sort = "u.$sort $dir"; + } else if (empty($sort)) { + $sort = "a.timemodified DESC"; + } else { + $sort = "a.$sort $dir"; + } + + /* not sure this is needed at all since assignmenet already has a course define, so this join? + $select = "s.course = '$assignment->course' AND"; + if ($assignment->course == SITEID) { + $select = ''; + }*/ + + return get_records_sql("SELECT a.* + FROM {$CFG->prefix}print_submissions a, + {$CFG->prefix}user u + WHERE u.id = a.userid + AND a.assignment = '$assignment->id' + ORDER BY $sort"); + + /* return get_records_sql("SELECT a.* + FROM {$CFG->prefix}assignment_submissions a, + {$CFG->prefix}user_students s, + {$CFG->prefix}user u + WHERE a.userid = s.userid + AND u.id = a.userid + AND $select a.assignment = '$assignment->id' + ORDER BY $sort"); + */ +} + +function print_add_instance($print) { + + + $print->timemodified = time(); + $print->courseid = $print->course; + + # You may have to add extra stuff in here # + + return insert_record('print', $print); +} + + +/** + * Given an object containing all the necessary data, + * (defined by the form in mod_form.php) this function + * will update an existing instance with new data. + * + * @param object $print An object from the form in mod_form.php + * @return boolean Success/Fail + */ +function print_update_instance($print) { + + $print->timemodified = time(); + $print->id = $print->instance; + + # You may have to add extra stuff in here # + + return update_record('print', $print); +} + + +/** + * Given an ID of an instance of this module, + * this function will permanently delete the instance + * and any data that depends on it. + * + * @param int $id Id of the module instance + * @return boolean Success/Failure + */ +function print_delete_instance($id) { + + if (! $print = get_record('print', 'id', $id)) { + return false; + } + + $result = true; + + # Delete any dependent records here # + + if (! delete_records('print', 'id', $print->id)) { + $result = false; + } + + return $result; +} + + +/** + * Return a small object with summary information about what a + * user has done with a given particular instance of this module + * Used for user activity reports. + * $return->time = the time they did it + * $return->info = a short text description + * + * @return null + * @todo Finish documenting this function + */ +function print_user_outline($course, $user, $mod, $print) { + return $return; +} + + +/** + * Print a detailed representation of what a user has done with + * a given particular instance of this module, for user activity reports. + * + * @return boolean + * @todo Finish documenting this function + */ +function print_user_complete($course, $user, $mod, $print) { + return true; +} + + +/** + * Given a course and a time, this module should find recent activity + * that has occurred in print activities and print it out. + * Return true if there was output, or false is there was none. + * + * @return boolean + * @todo Finish documenting this function + */ +function print_print_recent_activity($course, $isteacher, $timestart) { + return false; // True if anything was printed, otherwise false +} + + +/** + * Function to be run periodically according to the moodle cron + * This function searches for things that need to be done, such + * as sending out mail, toggling flags etc ... + * + * @return boolean + * @todo Finish documenting this function + **/ +function print_cron () { + return true; +} + + +/** + * Must return an array of user records (all data) who are participants + * for a given instance of print. Must include every user involved + * in the instance, independient of his role (student, teacher, admin...) + * See other modules as example. + * + * @param int $printid ID of an instance of this module + * @return mixed boolean/array of students + */ +function print_get_participants($printid) { + return false; +} + + +/** + * This function returns if a scale is being used by one print + * if it has support for grading and scales. Commented code should be + * modified if necessary. See forum, glossary or journal modules + * as reference. + * + * @param int $printid ID of an instance of this module + * @return mixed + * @todo Finish documenting this function + */ +function print_scale_used($printid, $scaleid) { + $return = false; + + //$rec = get_record("print","id","$printid","scale","-$scaleid"); + // + //if (!empty($rec) && !empty($scaleid)) { + // $return = true; + //} + + return $return; +} + + +/** + * Checks if scale is being used by any instance of print. + * This function was added in 1.9 + * + * This is used to find out if scale used anywhere + * @param $scaleid int + * @return boolean True if the scale is used by any print + */ +function print_scale_used_anywhere($scaleid) { + if ($scaleid and record_exists('print', 'grade', -$scaleid)) { + return true; + } else { + return false; + } +} + + +/** + * Execute post-install custom actions for the module + * This function was added in 1.9 + * + * @return boolean true if success, false on error + */ +function print_install() { + return true; +} + +function printit_real($file) { + + require_once('PrintIPP.php'); + require_once('CupsPrintIPP.php'); + $ipp = new CupsPrintIPP; + $ipp->getPrinters(); + $uri = $ipp->available_printers[0]; + #$ipp->setUserName($username='iwikiwi@localhost'); + #$ipp->setAuthentication('iwikiwi@localhost','dbzdbz'); + $ipp->setHost("localhost"); + $ipp->setPrinterURI($uri); + $ipp->setLog('log.txt'); + $ipp->setData($file); // Path to file. + $ipp->printJob(); + +} + + +/** + * Execute post-uninstall custom actions for the module + * This function was added in 1.9 + * + * @return boolean true if success, false on error + */ +function print_uninstall() { + return true; +} + + +////////////////////////////////////////////////////////////////////////////////////// +/// Any other print functions go here. Each of them must have a name that +/// starts with print_ +/// Remember (see note in first lines) that, if this section grows, it's HIGHLY +/// recommended to move all funcions below to a new "localib.php" file. + + +?> diff --git a/Moodle/mod/print/lib11.php b/Moodle/mod/print/lib11.php new file mode 100755 index 0000000..7b011f7 --- /dev/null +++ b/Moodle/mod/print/lib11.php @@ -0,0 +1,3090 @@ +cm = $cm; + } else if (! $this->cm = get_coursemodule_from_id('assignment', $cmid)) { + error('Course Module ID was incorrect'); + } + + $this->context = get_context_instance(CONTEXT_MODULE, $this->cm->id); + + if ($course) { + $this->course = $course; + } else if ($this->cm->course == $COURSE->id) { + $this->course = $COURSE; + } else if (! $this->course = get_record('course', 'id', $this->cm->course)) { + error('Course is misconfigured'); + } + + if ($assignment) { + $this->assignment = $assignment; + } else if (! $this->assignment = get_record('assignment', 'id', $this->cm->instance)) { + error('assignment ID was incorrect'); + } + + $this->assignment->cmidnumber = $this->cm->id; // compatibility with modedit assignment obj + $this->assignment->courseid = $this->course->id; // compatibility with modedit assignment obj + + $this->strassignment = get_string('modulename', 'assignment'); + $this->strassignments = get_string('modulenameplural', 'assignment'); + $this->strsubmissions = get_string('submissions', 'assignment'); + $this->strlastmodified = get_string('lastmodified'); + $this->pagetitle = strip_tags($this->course->shortname.': '.$this->strassignment.': '.format_string($this->assignment->name,true)); + + // visibility handled by require_login() with $cm parameter + // get current group only when really needed + + /// Set up things for a HTML editor if it's needed + if ($this->usehtmleditor = can_use_html_editor()) { + $this->defaultformat = FORMAT_HTML; + } else { + $this->defaultformat = FORMAT_MOODLE; + } + } + + /** + * Display the assignment, used by view.php + * + * This in turn calls the methods producing individual parts of the page + */ + function view() { + + $context = get_context_instance(CONTEXT_MODULE,$this->cm->id); + require_capability('mod/assignment:view', $context); + + add_to_log($this->course->id, "assignment", "view", "view.php?id={$this->cm->id}", + $this->assignment->id, $this->cm->id); + + $this->view_header(); + + $this->view_intro(); + + $this->view_dates(); + + $this->view_feedback(); + + $this->view_footer(); + } + + /** + * Display the header and top of a page + * + * (this doesn't change much for assignment types) + * This is used by the view() method to print the header of view.php but + * it can be used on other pages in which case the string to denote the + * page in the navigation trail should be passed as an argument + * + * @param $subpage string Description of subpage to be used in navigation trail + */ + function view_header($subpage='') { + + global $CFG; + + + if ($subpage) { + $navigation = build_navigation($subpage, $this->cm); + } else { + $navigation = build_navigation('', $this->cm); + } + + print_header($this->pagetitle, $this->course->fullname, $navigation, '', '', + true, update_module_button($this->cm->id, $this->course->id, $this->strassignment), + navmenu($this->course, $this->cm)); + + groups_print_activity_menu($this->cm, 'view.php?id=' . $this->cm->id); + + echo ''; + echo '
'; + } + + + /** + * Display the assignment intro + * + * This will most likely be extended by assignment type plug-ins + * The default implementation prints the assignment description in a box + */ + function view_intro() { + print_simple_box_start('center', '', '', 0, 'generalbox', 'intro'); + $formatoptions = new stdClass; + $formatoptions->noclean = true; + echo format_text($this->assignment->description, $this->assignment->format, $formatoptions); + print_simple_box_end(); + } + + /** + * Display the assignment dates + * + * Prints the assignment start and end dates in a box. + * This will be suitable for most assignment types + */ + function view_dates() { + if (!$this->assignment->timeavailable && !$this->assignment->timedue) { + return; + } + + print_simple_box_start('center', '', '', 0, 'generalbox', 'dates'); + echo ''; + if ($this->assignment->timeavailable) { + echo ''; + echo ' '; + } + if ($this->assignment->timedue) { + echo ''; + echo ' '; + } + echo '
'.get_string('availabledate','assignment').':'.userdate($this->assignment->timeavailable).'
'.get_string('duedate','assignment').':'.userdate($this->assignment->timedue).'
'; + print_simple_box_end(); + } + + + /** + * Display the bottom and footer of a page + * + * This default method just prints the footer. + * This will be suitable for most assignment types + */ + function view_footer() { + print_footer($this->course); + } + + /** + * Display the feedback to the student + * + * This default method prints the teacher picture and name, date when marked, + * grade and teacher submissioncomment. + * + * @param $submission object The submission object or NULL in which case it will be loaded + */ + function view_feedback($submission=NULL) { + global $USER, $CFG; + require_once($CFG->libdir.'/gradelib.php'); + + if (!has_capability('mod/assignment:submit', $this->context, $USER->id, false)) { + // can not submit assignments -> no feedback + return; + } + + if (!$submission) { /// Get submission for this assignment + $submission = $this->get_submission($USER->id); + } + + $grading_info = grade_get_grades($this->course->id, 'mod', 'assignment', $this->assignment->id, $USER->id); + $item = $grading_info->items[0]; + $grade = $item->grades[$USER->id]; + + if ($grade->hidden or $grade->grade === false) { // hidden or error + return; + } + + if ($grade->grade === null and empty($grade->str_feedback)) { /// Nothing to show yet + return; + } + + $graded_date = $grade->dategraded; + $graded_by = $grade->usermodified; + + /// We need the teacher info + if (!$teacher = get_record('user', 'id', $graded_by)) { + error('Could not find the teacher'); + } + + /// Print the feedback + print_heading(get_string('feedbackfromteacher', 'assignment', $this->course->teacher)); // TODO: fix teacher string + + echo ''; + + echo ''; + echo ''; + echo ''; + echo ''; + + echo ''; + echo ''; + echo ''; + + echo ''; + } + + /** + * Returns a link with info about the state of the assignment submissions + * + * This is used by view_header to put this link at the top right of the page. + * For teachers it gives the number of submitted assignments with a link + * For students it gives the time of their submission. + * This will be suitable for most assignment types. + * @param bool $allgroup print all groups info if user can access all groups, suitable for index.php + * @return string + */ + function submittedlink($allgroups=false) { + global $USER; + + $submitted = ''; + + $context = get_context_instance(CONTEXT_MODULE,$this->cm->id); + if (has_capability('mod/assignment:grade', $context)) { + if ($allgroups and has_capability('moodle/site:accessallgroups', $context)) { + $group = 0; + } else { + $group = groups_get_activity_group($this->cm); + } + if ($count = $this->count_real_submissions($group)) { + $submitted = ''. + get_string('viewsubmissions', 'assignment', $count).''; + } else { + $submitted = ''. + get_string('noattempts', 'assignment').''; + } + } else { + if (!empty($USER->id)) { + if ($submission = $this->get_submission($USER->id)) { + if ($submission->timemodified) { + if ($submission->timemodified <= $this->assignment->timedue || empty($this->assignment->timedue)) { + $submitted = ''.userdate($submission->timemodified).''; + } else { + $submitted = ''.userdate($submission->timemodified).''; + } + } + } + } + } + + return $submitted; + } + + + function setup_elements(&$mform) { + + } + + /** + * Create a new assignment activity + * + * Given an object containing all the necessary data, + * (defined by the form in mod.html) this function + * will create a new instance and return the id number + * of the new instance. + * The due data is added to the calendar + * This is common to all assignment types. + * + * @param $assignment object The data from the form on mod.html + * @return int The id of the assignment + */ + function add_instance($assignment) { + global $COURSE; + + $assignment->timemodified = time(); + $assignment->courseid = $assignment->course; + + if ($returnid = insert_record("assignment", $assignment)) { + $assignment->id = $returnid; + + if ($assignment->timedue) { + $event = new object(); + $event->name = $assignment->name; + $event->description = $assignment->description; + $event->courseid = $assignment->course; + $event->groupid = 0; + $event->userid = 0; + $event->modulename = 'assignment'; + $event->instance = $returnid; + $event->eventtype = 'due'; + $event->timestart = $assignment->timedue; + $event->timeduration = 0; + + add_event($event); + } + + $assignment = stripslashes_recursive($assignment); + assignment_grade_item_update($assignment); + + } + + + return $returnid; + } + + /** + * Deletes an assignment activity + * + * Deletes all database records, files and calendar events for this assignment. + * @param $assignment object The assignment to be deleted + * @return boolean False indicates error + */ + function delete_instance($assignment) { + global $CFG; + + $assignment->courseid = $assignment->course; + + $result = true; + + if (! delete_records('assignment_submissions', 'assignment', $assignment->id)) { + $result = false; + } + + if (! delete_records('assignment', 'id', $assignment->id)) { + $result = false; + } + + if (! delete_records('event', 'modulename', 'assignment', 'instance', $assignment->id)) { + $result = false; + } + + // delete file area with all attachments - ignore errors + require_once($CFG->libdir.'/filelib.php'); + fulldelete($CFG->dataroot.'/'.$assignment->course.'/'.$CFG->moddata.'/assignment/'.$assignment->id); + + assignment_grade_item_delete($assignment); + + return $result; + } + + /** + * Updates a new assignment activity + * + * Given an object containing all the necessary data, + * (defined by the form in mod.html) this function + * will update the assignment instance and return the id number + * The due date is updated in the calendar + * This is common to all assignment types. + * + * @param $assignment object The data from the form on mod.html + * @return int The assignment id + */ + function update_instance($assignment) { + global $COURSE; + + $assignment->timemodified = time(); + + $assignment->id = $assignment->instance; + $assignment->courseid = $assignment->course; + + if (!update_record('assignment', $assignment)) { + return false; + } + + if ($assignment->timedue) { + $event = new object(); + + if ($event->id = get_field('event', 'id', 'modulename', 'assignment', 'instance', $assignment->id)) { + + $event->name = $assignment->name; + $event->description = $assignment->description; + $event->timestart = $assignment->timedue; + + update_event($event); + } else { + $event = new object(); + $event->name = $assignment->name; + $event->description = $assignment->description; + $event->courseid = $assignment->course; + $event->groupid = 0; + $event->userid = 0; + $event->modulename = 'assignment'; + $event->instance = $assignment->id; + $event->eventtype = 'due'; + $event->timestart = $assignment->timedue; + $event->timeduration = 0; + + add_event($event); + } + } else { + delete_records('event', 'modulename', 'assignment', 'instance', $assignment->id); + } + + // get existing grade item + $assignment = stripslashes_recursive($assignment); + + assignment_grade_item_update($assignment); + + return true; + } + + /** + * Update grade item for this submission. + */ + function update_grade($submission) { + assignment_update_grades($this->assignment, $submission->userid); + } + + /** + * Top-level function for handling of submissions called by submissions.php + * + * This is for handling the teacher interaction with the grading interface + * This should be suitable for most assignment types. + * + * @param $mode string Specifies the kind of teacher interaction taking place + */ + function submissions($mode) { + ///The main switch is changed to facilitate + ///1) Batch fast grading + ///2) Skip to the next one on the popup + ///3) Save and Skip to the next one on the popup + + //make user global so we can use the id + global $USER; + + $mailinfo = optional_param('mailinfo', null, PARAM_BOOL); + if (is_null($mailinfo)) { + $mailinfo = get_user_preferences('assignment_mailinfo', 0); + } else { + set_user_preference('assignment_mailinfo', $mailinfo); + } + + switch ($mode) { + case 'grade': // We are in a popup window grading + if ($submission = $this->process_feedback()) { + //IE needs proper header with encoding + print_header(get_string('feedback', 'assignment').':'.format_string($this->assignment->name)); + print_heading(get_string('changessaved')); + print $this->update_main_listing($submission); + } + close_window(); + break; + + case 'single': // We are in a popup window displaying submission + $this->display_submission(); + break; + + case 'all': // Main window, display everything + $this->display_submissions(); + break; + + case 'fastgrade': + ///do the fast grading stuff - this process should work for all 3 subclasses + + $grading = false; + $commenting = false; + $col = false; + if (isset($_POST['submissioncomment'])) { + $col = 'submissioncomment'; + $commenting = true; + } + if (isset($_POST['menu'])) { + $col = 'menu'; + $grading = true; + } + if (!$col) { + //both submissioncomment and grade columns collapsed.. + $this->display_submissions(); + break; + } + + foreach ($_POST[$col] as $id => $unusedvalue){ + + $id = (int)$id; //clean parameter name + + $this->process_outcomes($id); + + if (!$submission = $this->get_submission($id)) { + $submission = $this->prepare_new_submission($id); + $newsubmission = true; + } else { + $newsubmission = false; + } + unset($submission->data1); // Don't need to update this. + unset($submission->data2); // Don't need to update this. + + //for fast grade, we need to check if any changes take place + $updatedb = false; + + if ($grading) { + $grade = $_POST['menu'][$id]; + $updatedb = $updatedb || ($submission->grade != $grade); + $submission->grade = $grade; + } else { + if (!$newsubmission) { + unset($submission->grade); // Don't need to update this. + } + } + if ($commenting) { + $commentvalue = trim($_POST['submissioncomment'][$id]); + $updatedb = $updatedb || ($submission->submissioncomment != stripslashes($commentvalue)); + $submission->submissioncomment = $commentvalue; + } else { + unset($submission->submissioncomment); // Don't need to update this. + } + + $submission->teacher = $USER->id; + if ($updatedb) { + $submission->mailed = (int)(!$mailinfo); + } + + $submission->timemarked = time(); + + //if it is not an update, we don't change the last modified time etc. + //this will also not write into database if no submissioncomment and grade is entered. + + if ($updatedb){ + if ($newsubmission) { + if (!isset($submission->submissioncomment)) { + $submission->submissioncomment = ''; + } + if (!$sid = insert_record('assignment_submissions', $submission)) { + return false; + } + $submission->id = $sid; + } else { + if (!update_record('assignment_submissions', $submission)) { + return false; + } + } + + // triger grade event + $this->update_grade($submission); + + //add to log only if updating + add_to_log($this->course->id, 'assignment', 'update grades', + 'submissions.php?id='.$this->assignment->id.'&user='.$submission->userid, + $submission->userid, $this->cm->id); + } + + } + + $message = notify(get_string('changessaved'), 'notifysuccess', 'center', true); + + $this->display_submissions($message); + break; + + + case 'next': + /// We are currently in pop up, but we want to skip to next one without saving. + /// This turns out to be similar to a single case + /// The URL used is for the next submission. + + $this->display_submission(); + break; + + case 'saveandnext': + ///We are in pop up. save the current one and go to the next one. + //first we save the current changes + if ($submission = $this->process_feedback()) { + //print_heading(get_string('changessaved')); + $extra_javascript = $this->update_main_listing($submission); + } + + //then we display the next submission + $this->display_submission($extra_javascript); + break; + + default: + echo "something seriously is wrong!!"; + break; + } + } + + /** + * Helper method updating the listing on the main script from popup using javascript + * + * @param $submission object The submission whose data is to be updated on the main page + */ + function update_main_listing($submission) { + global $SESSION, $CFG; + + $output = ''; + + $perpage = get_user_preferences('assignment_perpage', 10); + + $quickgrade = get_user_preferences('assignment_quickgrade', 0); + + /// Run some Javascript to try and update the parent page + $output .= '"; + return $output; + } + + /** + * Return a grade in user-friendly form, whether it's a scale or not + * + * @param $grade + * @return string User-friendly representation of grade + */ + function display_grade($grade) { + + static $scalegrades = array(); // Cache scales for each assignment - they might have different scales!! + + if ($this->assignment->grade >= 0) { // Normal number + if ($grade == -1) { + return '-'; + } else { + return $grade.' / '.$this->assignment->grade; + } + + } else { // Scale + if (empty($scalegrades[$this->assignment->id])) { + if ($scale = get_record('scale', 'id', -($this->assignment->grade))) { + $scalegrades[$this->assignment->id] = make_menu_from_list($scale->scale); + } else { + return '-'; + } + } + if (isset($scalegrades[$this->assignment->id][$grade])) { + return $scalegrades[$this->assignment->id][$grade]; + } + return '-'; + } + } + + /** + * Display a single submission, ready for grading on a popup window + * + * This default method prints the teacher info and submissioncomment box at the top and + * the student info and submission at the bottom. + * This method also fetches the necessary data in order to be able to + * provide a "Next submission" button. + * Calls preprocess_submission() to give assignment type plug-ins a chance + * to process submissions before they are graded + * This method gets its arguments from the page parameters userid and offset + */ + function display_submission($extra_javascript = '') { + + global $CFG; + require_once($CFG->libdir.'/gradelib.php'); + require_once($CFG->libdir.'/tablelib.php'); + + $userid = required_param('userid', PARAM_INT); + $offset = required_param('offset', PARAM_INT);//offset for where to start looking for student. + + if (!$user = get_record('user', 'id', $userid)) { + error('No such user!'); + } + + if (!$submission = $this->get_submission($user->id)) { + $submission = $this->prepare_new_submission($userid); + } + if ($submission->timemodified > $submission->timemarked) { + $subtype = 'assignmentnew'; + } else { + $subtype = 'assignmentold'; + } + + $grading_info = grade_get_grades($this->course->id, 'mod', 'assignment', $this->assignment->id, array($user->id)); + $disabled = $grading_info->items[0]->grades[$userid]->locked || $grading_info->items[0]->grades[$userid]->overridden; + + /// construct SQL, using current offset to find the data of the next student + $course = $this->course; + $assignment = $this->assignment; + $cm = $this->cm; + $context = get_context_instance(CONTEXT_MODULE, $cm->id); + + /// Get all ppl that can submit assignments + + $currentgroup = groups_get_activity_group($cm); + if ($users = get_users_by_capability($context, 'mod/assignment:submit', 'u.id', '', '', '', $currentgroup, '', false)) { + $users = array_keys($users); + } + + // if groupmembersonly used, remove users who are not in any group + if ($users and !empty($CFG->enablegroupings) and $cm->groupmembersonly) { + if ($groupingusers = groups_get_grouping_members($cm->groupingid, 'u.id', 'u.id')) { + $users = array_intersect($users, array_keys($groupingusers)); + } + } + + $nextid = 0; + + if ($users) { + $select = 'SELECT u.id, u.firstname, u.lastname, u.picture, u.imagealt, + s.id AS submissionid, s.grade, s.submissioncomment, + s.timemodified, s.timemarked, + COALESCE(SIGN(SIGN(s.timemarked) + SIGN(s.timemarked - s.timemodified)), 0) AS status '; + $sql = 'FROM '.$CFG->prefix.'user u '. + 'LEFT JOIN '.$CFG->prefix.'assignment_submissions s ON u.id = s.userid + AND s.assignment = '.$this->assignment->id.' '. + 'WHERE u.id IN ('.implode(',', $users).') '; + + if ($sort = flexible_table::get_sql_sort('mod-assignment-submissions')) { + $sort = 'ORDER BY '.$sort.' '; + } + + if (($auser = get_records_sql($select.$sql.$sort, $offset+1, 1)) !== false) { + $nextuser = array_shift($auser); + /// Calculate user status + $nextuser->status = ($nextuser->timemarked > 0) && ($nextuser->timemarked >= $nextuser->timemodified); + $nextid = $nextuser->id; + } + } + + print_header(get_string('feedback', 'assignment').':'.fullname($user, true).':'.format_string($this->assignment->name)); + + /// Print any extra javascript needed for saveandnext + echo $extra_javascript; + + ///SOme javascript to help with setting up >.> + + echo ''."\n"; + echo ''; + + ///Start of teacher info row + + echo ''; + echo ''; + echo ''; + + ///End of teacher info row, Start of student info row + echo ''; + echo ''; + echo ''; + echo ''; + + ///End of student info row + + echo ''; + + if (!$disabled and $this->usehtmleditor) { + use_html_editor(); + } + + print_footer('none'); + } + + /** + * Preprocess submission before grading + * + * Called by display_submission() + * The default type does nothing here. + * @param $submission object The submission object + */ + function preprocess_submission(&$submission) { + } + + /** + * Display all the submissions ready for grading + */ + function display_submissions($message='') { + global $CFG, $db, $USER; + require_once($CFG->libdir.'/gradelib.php'); + + /* first we check to see if the form has just been submitted + * to request user_preference updates + */ + + if (isset($_POST['updatepref'])){ + $perpage = optional_param('perpage', 10, PARAM_INT); + $perpage = ($perpage <= 0) ? 10 : $perpage ; + set_user_preference('assignment_perpage', $perpage); + set_user_preference('assignment_quickgrade', optional_param('quickgrade', 0, PARAM_BOOL)); + } + + /* next we get perpage and quickgrade (allow quick grade) params + * from database + */ + $perpage = get_user_preferences('assignment_perpage', 10); + + $quickgrade = get_user_preferences('assignment_quickgrade', 0); + + $grading_info = grade_get_grades($this->course->id, 'mod', 'assignment', $this->assignment->id); + + if (!empty($CFG->enableoutcomes) and !empty($grading_info->outcomes)) { + $uses_outcomes = true; + } else { + $uses_outcomes = false; + } + + $page = optional_param('page', 0, PARAM_INT); + $strsaveallfeedback = get_string('saveallfeedback', 'assignment'); + + /// Some shortcuts to make the code read better + + $course = $this->course; + $assignment = $this->assignment; + $cm = $this->cm; + + $tabindex = 1; //tabindex for quick grading tabbing; Not working for dropdowns yet + add_to_log($course->id, 'assignment', 'view submission', 'submissions.php?id='.$this->cm->id, $this->assignment->id, $this->cm->id); + $navigation = build_navigation($this->strsubmissions, $this->cm); + print_header_simple(format_string($this->assignment->name,true), "", $navigation, + '', '', true, update_module_button($cm->id, $course->id, $this->strassignment), navmenu($course, $cm)); + + $course_context = get_context_instance(CONTEXT_COURSE, $course->id); + if (has_capability('gradereport/grader:view', $course_context) && has_capability('moodle/grade:viewall', $course_context)) { + echo ''; + } + + if (!empty($message)) { + echo $message; // display messages here if any + } + + $context = get_context_instance(CONTEXT_MODULE, $cm->id); + + /// Check to see if groups are being used in this assignment + + /// find out current groups mode + $groupmode = groups_get_activity_groupmode($cm); + $currentgroup = groups_get_activity_group($cm, true); + groups_print_activity_menu($cm, 'submissions.php?id=' . $this->cm->id); + + /// Get all ppl that are allowed to submit assignments + if ($users = get_users_by_capability($context, 'mod/assignment:submit', 'u.id', '', '', '', $currentgroup, '', false)) { + $users = array_keys($users); + } + + // if groupmembersonly used, remove users who are not in any group + if ($users and !empty($CFG->enablegroupings) and $cm->groupmembersonly) { + if ($groupingusers = groups_get_grouping_members($cm->groupingid, 'u.id', 'u.id')) { + $users = array_intersect($users, array_keys($groupingusers)); + } + } + + $tablecolumns = array('picture', 'fullname', 'grade', 'submissioncomment', 'timemodified', 'timemarked', 'status', 'finalgrade'); + if ($uses_outcomes) { + $tablecolumns[] = 'outcome'; // no sorting based on outcomes column + } + + $tableheaders = array('', + get_string('fullname'), + get_string('grade'), + get_string('comment', 'assignment'), + get_string('lastmodified').' ('.$course->student.')', + get_string('lastmodified').' ('.$course->teacher.')', + get_string('status'), + get_string('finalgrade', 'grades')); + if ($uses_outcomes) { + $tableheaders[] = get_string('outcome', 'grades'); + } + + require_once($CFG->libdir.'/tablelib.php'); + $table = new flexible_table('mod-assignment-submissions'); + + $table->define_columns($tablecolumns); + $table->define_headers($tableheaders); + $table->define_baseurl($CFG->wwwroot.'/mod/assignment/submissions.php?id='.$this->cm->id.'&currentgroup='.$currentgroup); + + $table->sortable(true, 'lastname');//sorted by lastname by default + $table->collapsible(true); + $table->initialbars(true); + + $table->column_suppress('picture'); + $table->column_suppress('fullname'); + + $table->column_class('picture', 'picture'); + $table->column_class('fullname', 'fullname'); + $table->column_class('grade', 'grade'); + $table->column_class('submissioncomment', 'comment'); + $table->column_class('timemodified', 'timemodified'); + $table->column_class('timemarked', 'timemarked'); + $table->column_class('status', 'status'); + $table->column_class('finalgrade', 'finalgrade'); + if ($uses_outcomes) { + $table->column_class('outcome', 'outcome'); + } + + $table->set_attribute('cellspacing', '0'); + $table->set_attribute('id', 'attempts'); + $table->set_attribute('class', 'submissions'); + $table->set_attribute('width', '100%'); + //$table->set_attribute('align', 'center'); + + $table->no_sorting('finalgrade'); + $table->no_sorting('outcome'); + + // Start working -- this is necessary as soon as the niceties are over + $table->setup(); + + if (empty($users)) { + print_heading(get_string('nosubmitusers','assignment')); + return true; + } + + /// Construct the SQL + + if ($where = $table->get_sql_where()) { + $where .= ' AND '; + } + + if ($sort = $table->get_sql_sort()) { + $sort = ' ORDER BY '.$sort; + } + + $select = 'SELECT u.id, u.firstname, u.lastname, u.picture, u.imagealt, + s.id AS submissionid, s.grade, s.submissioncomment, + s.timemodified, s.timemarked, + COALESCE(SIGN(SIGN(s.timemarked) + SIGN(s.timemarked - s.timemodified)), 0) AS status '; + $sql = 'FROM '.$CFG->prefix.'user u '. + 'LEFT JOIN '.$CFG->prefix.'assignment_submissions s ON u.id = s.userid + AND s.assignment = '.$this->assignment->id.' '. + 'WHERE '.$where.'u.id IN ('.implode(',',$users).') '; + + $table->pagesize($perpage, count($users)); + + ///offset used to calculate index of student in that particular query, needed for the pop up to know who's next + $offset = $page * $perpage; + + $strupdate = get_string('update'); + $strgrade = get_string('grade'); + $grademenu = make_grades_menu($this->assignment->grade); + + if (($ausers = get_records_sql($select.$sql.$sort, $table->get_page_start(), $table->get_page_size())) !== false) { + $grading_info = grade_get_grades($this->course->id, 'mod', 'assignment', $this->assignment->id, array_keys($ausers)); + foreach ($ausers as $auser) { + $final_grade = $grading_info->items[0]->grades[$auser->id]; + $grademax = $grading_info->items[0]->grademax; + $final_grade->formatted_grade = round($final_grade->grade,2) .' / ' . round($grademax,2); + $locked_overridden = 'locked'; + if ($final_grade->overridden) { + $locked_overridden = 'overridden'; + } + + /// Calculate user status + $auser->status = ($auser->timemarked > 0) && ($auser->timemarked >= $auser->timemodified); + $picture = print_user_picture($auser, $course->id, $auser->picture, false, true); + + if (empty($auser->submissionid)) { + $auser->grade = -1; //no submission yet + } + + if (!empty($auser->submissionid)) { + ///Prints student answer and student modified date + ///attach file or print link to student answer, depending on the type of the assignment. + ///Refer to print_student_answer in inherited classes. + if ($auser->timemodified > 0) { + $studentmodified = '
'.$this->print_student_answer($auser->id) + . userdate($auser->timemodified).'
'; + } else { + $studentmodified = '
 
'; + } + ///Print grade, dropdown or text + if ($auser->timemarked > 0) { + $teachermodified = '
'.userdate($auser->timemarked).'
'; + + if ($final_grade->locked or $final_grade->overridden) { + $grade = '
'.$final_grade->formatted_grade.'
'; + } else if ($quickgrade) { + $menu = choose_from_menu(make_grades_menu($this->assignment->grade), + 'menu['.$auser->id.']', $auser->grade, + get_string('nograde'),'',-1,true,false,$tabindex++); + $grade = '
'. $menu .'
'; + } else { + $grade = '
'.$this->display_grade($auser->grade).'
'; + } + + } else { + $teachermodified = '
 
'; + if ($final_grade->locked or $final_grade->overridden) { + $grade = '
'.$final_grade->formatted_grade.'
'; + } else if ($quickgrade) { + $menu = choose_from_menu(make_grades_menu($this->assignment->grade), + 'menu['.$auser->id.']', $auser->grade, + get_string('nograde'),'',-1,true,false,$tabindex++); + $grade = '
'.$menu.'
'; + } else { + $grade = '
'.$this->display_grade($auser->grade).'
'; + } + } + ///Print Comment + if ($final_grade->locked or $final_grade->overridden) { + $comment = '
'.shorten_text(strip_tags($final_grade->str_feedback),15).'
'; + + } else if ($quickgrade) { + $comment = '
' + . '
'; + } else { + $comment = '
'.shorten_text(strip_tags($auser->submissioncomment),15).'
'; + } + } else { + $studentmodified = '
 
'; + $teachermodified = '
 
'; + $status = '
 
'; + + if ($final_grade->locked or $final_grade->overridden) { + $grade = '
'.$final_grade->formatted_grade . '
'; + } else if ($quickgrade) { // allow editing + $menu = choose_from_menu(make_grades_menu($this->assignment->grade), + 'menu['.$auser->id.']', $auser->grade, + get_string('nograde'),'',-1,true,false,$tabindex++); + $grade = '
'.$menu.'
'; + } else { + $grade = '
-
'; + } + + if ($final_grade->locked or $final_grade->overridden) { + $comment = '
'.$final_grade->str_feedback.'
'; + } else if ($quickgrade) { + $comment = '
' + . '
'; + } else { + $comment = '
 
'; + } + } + + if (empty($auser->status)) { /// Confirm we have exclusively 0 or 1 + $auser->status = 0; + } else { + $auser->status = 1; + } + + $buttontext = ($auser->status == 1) ? $strupdate : $strgrade; + + ///No more buttons, we use popups ;-). + $popup_url = '/mod/assignment/submissions.php?id='.$this->cm->id + . '&userid='.$auser->id.'&mode=single'.'&offset='.$offset++; + $button = link_to_popup_window ($popup_url, 'grade'.$auser->id, $buttontext, 600, 780, + $buttontext, 'none', true, 'button'.$auser->id); + + $status = '
'.$button.'
'; + + $finalgrade = ''.$final_grade->str_grade.''; + + $outcomes = ''; + + if ($uses_outcomes) { + + foreach($grading_info->outcomes as $n=>$outcome) { + $outcomes .= '
'; + $options = make_grades_menu(-$outcome->scaleid); + + if ($outcome->grades[$auser->id]->locked or !$quickgrade) { + $options[0] = get_string('nooutcome', 'grades'); + $outcomes .= ': '.$options[$outcome->grades[$auser->id]->grade].''; + } else { + $outcomes .= ' '; + $outcomes .= choose_from_menu($options, 'outcome_'.$n.'['.$auser->id.']', + $outcome->grades[$auser->id]->grade, get_string('nooutcome', 'grades'), '', 0, true, false, 0, 'outcome_'.$n.'_'.$auser->id); + } + $outcomes .= '
'; + } + } + + $userlink = '' . fullname($auser) . ''; + $row = array($picture, $userlink, $grade, $comment, $studentmodified, $teachermodified, $status, $finalgrade); + if ($uses_outcomes) { + $row[] = $outcomes; + } + + $table->add_data($row); + } + } + + /// Print quickgrade form around the table + if ($quickgrade){ + echo '
'; + echo '
'; + echo ''; + echo ''; + echo ''; + echo '
'; + } + + $table->print_html(); /// Print the whole table + + if ($quickgrade){ + $lastmailinfo = get_user_preferences('assignment_mailinfo', 1) ? 'checked="checked"' : ''; + echo '
'; + echo '
'; + echo ''; + echo ''; + echo ''; + helpbutton('emailnotification', get_string('enableemailnotification', 'assignment'), 'assignment').'

'; + echo '
'; + echo '
'; + echo ''; + echo '
'; + } + /// End of fast grading form + + /// Mini form for setting user preference + echo '
'; + echo '
'; + echo ''; + echo ''; + echo ''; + echo ''; + echo ''; + echo ''; + echo '
'; + echo ''; + echo ''; + echo ''; + helpbutton('pagesize', get_string('pagesize','assignment'), 'assignment'); + echo '
'; + echo ''; + echo ''; + $checked = $quickgrade ? 'checked="checked"' : ''; + echo ''; + helpbutton('quickgrade', get_string('quickgrade', 'assignment'), 'assignment').'

'; + echo '
'; + echo ''; + echo '
'; + echo '
'; + ///End of mini form + print_footer($this->course); + } + + /** + * Process teacher feedback submission + * + * This is called by submissions() when a grading even has taken place. + * It gets its data from the submitted form. + * @return object The updated submission object + */ + function process_feedback() { + global $CFG, $USER; + require_once($CFG->libdir.'/gradelib.php'); + + if (!$feedback = data_submitted()) { // No incoming data? + return false; + } + + ///For save and next, we need to know the userid to save, and the userid to go + ///We use a new hidden field in the form, and set it to -1. If it's set, we use this + ///as the userid to store + if ((int)$feedback->saveuserid !== -1){ + $feedback->userid = $feedback->saveuserid; + } + + if (!empty($feedback->cancel)) { // User hit cancel button + return false; + } + + $grading_info = grade_get_grades($this->course->id, 'mod', 'assignment', $this->assignment->id, $feedback->userid); + + // store outcomes if needed + $this->process_outcomes($feedback->userid); + + $submission = $this->get_submission($feedback->userid, true); // Get or make one + + if (!$grading_info->items[0]->grades[$feedback->userid]->locked and + !$grading_info->items[0]->grades[$feedback->userid]->overridden) { + + $submission->grade = $feedback->grade; + $submission->submissioncomment = $feedback->submissioncomment; + $submission->format = $feedback->format; + $submission->teacher = $USER->id; + $mailinfo = get_user_preferences('assignment_mailinfo', 0); + if (!$mailinfo) { + $submission->mailed = 1; // treat as already mailed + } else { + $submission->mailed = 0; // Make sure mail goes out (again, even) + } + $submission->timemarked = time(); + + unset($submission->data1); // Don't need to update this. + unset($submission->data2); // Don't need to update this. + + if (empty($submission->timemodified)) { // eg for offline assignments + // $submission->timemodified = time(); + } + + if (! update_record('assignment_submissions', $submission)) { + return false; + } + + // triger grade event + $this->update_grade($submission); + + add_to_log($this->course->id, 'assignment', 'update grades', + 'submissions.php?id='.$this->assignment->id.'&user='.$feedback->userid, $feedback->userid, $this->cm->id); + } + + return $submission; + + } + + function process_outcomes($userid) { + global $CFG, $USER; + + if (empty($CFG->enableoutcomes)) { + return; + } + + require_once($CFG->libdir.'/gradelib.php'); + + if (!$formdata = data_submitted()) { + return; + } + + $data = array(); + $grading_info = grade_get_grades($this->course->id, 'mod', 'assignment', $this->assignment->id, $userid); + + if (!empty($grading_info->outcomes)) { + foreach($grading_info->outcomes as $n=>$old) { + $name = 'outcome_'.$n; + if (isset($formdata->{$name}[$userid]) and $old->grades[$userid]->grade != $formdata->{$name}[$userid]) { + $data[$n] = $formdata->{$name}[$userid]; + } + } + } + if (count($data) > 0) { + grade_update_outcomes('mod/assignment', $this->course->id, 'mod', 'assignment', $this->assignment->id, $userid, $data); + } + + } + + /** + * Load the submission object for a particular user + * + * @param $userid int The id of the user whose submission we want or 0 in which case USER->id is used + * @param $createnew boolean optional Defaults to false. If set to true a new submission object will be created in the database + * @param bool $teachermodified student submission set if false + * @return object The submission + */ + function get_submission($userid=0, $createnew=false, $teachermodified=false) { + global $USER; + + if (empty($userid)) { + $userid = $USER->id; + } + + $submission = get_record('assignment_submissions', 'assignment', $this->assignment->id, 'userid', $userid); + + if ($submission || !$createnew) { + return $submission; + } + $newsubmission = $this->prepare_new_submission($userid, $teachermodified); + if (!insert_record("assignment_submissions", $newsubmission)) { + error("Could not insert a new empty submission"); + } + + return get_record('assignment_submissions', 'assignment', $this->assignment->id, 'userid', $userid); + } + + /** + * Instantiates a new submission object for a given user + * + * Sets the assignment, userid and times, everything else is set to default values. + * @param $userid int The userid for which we want a submission object + * @param bool $teachermodified student submission set if false + * @return object The submission + */ + function prepare_new_submission($userid, $teachermodified=false) { + $submission = new Object; + $submission->assignment = $this->assignment->id; + $submission->userid = $userid; + //$submission->timecreated = time(); + $submission->timecreated = ''; + // teachers should not be modifying modified date, except offline assignments + if ($teachermodified) { + $submission->timemodified = 0; + } else { + $submission->timemodified = $submission->timecreated; + } + $submission->numfiles = 0; + $submission->data1 = ''; + $submission->data2 = ''; + $submission->grade = -1; + $submission->submissioncomment = ''; + $submission->format = 0; + $submission->teacher = 0; + $submission->timemarked = 0; + $submission->mailed = 0; + return $submission; + } + + /** + * Return all assignment submissions by ENROLLED students (even empty) + * + * @param $sort string optional field names for the ORDER BY in the sql query + * @param $dir string optional specifying the sort direction, defaults to DESC + * @return array The submission objects indexed by id + */ + function get_submissions($sort='', $dir='DESC') { + return assignment_get_all_submissions($this->assignment, $sort, $dir); + } + + /** + * Counts all real assignment submissions by ENROLLED students (not empty ones) + * + * @param $groupid int optional If nonzero then count is restricted to this group + * @return int The number of submissions + */ + function count_real_submissions($groupid=0) { + return assignment_count_real_submissions($this->cm, $groupid); + } + + /** + * Alerts teachers by email of new or changed assignments that need grading + * + * First checks whether the option to email teachers is set for this assignment. + * Sends an email to ALL teachers in the course (or in the group if using separate groups). + * Uses the methods email_teachers_text() and email_teachers_html() to construct the content. + * @param $submission object The submission that has changed + */ + function email_teachers($submission) { + global $CFG; + + if (empty($this->assignment->emailteachers)) { // No need to do anything + return; + } + + $user = get_record('user', 'id', $submission->userid); + + if ($teachers = $this->get_graders($user)) { + + $strassignments = get_string('modulenameplural', 'assignment'); + $strassignment = get_string('modulename', 'assignment'); + $strsubmitted = get_string('submitted', 'assignment'); + + foreach ($teachers as $teacher) { + $info = new object(); + $info->username = fullname($user, true); + $info->assignment = format_string($this->assignment->name,true); + $info->url = $CFG->wwwroot.'/mod/assignment/submissions.php?id='.$this->cm->id; + + $postsubject = $strsubmitted.': '.$info->username.' -> '.$this->assignment->name; + $posttext = $this->email_teachers_text($info); + $posthtml = ($teacher->mailformat == 1) ? $this->email_teachers_html($info) : ''; + + @email_to_user($teacher, $user, $postsubject, $posttext, $posthtml); // If it fails, oh well, too bad. + } + } + } + + /** + * Returns a list of teachers that should be grading given submission + */ + function get_graders($user) { + //potential graders + $potgraders = get_users_by_capability($this->context, 'mod/assignment:grade', '', '', '', '', '', '', false, false); + + $graders = array(); + if (groups_get_activity_groupmode($this->cm) == SEPARATEGROUPS) { // Separate groups are being used + if ($groups = groups_get_all_groups($this->course->id, $user->id)) { // Try to find all groups + foreach ($groups as $group) { + foreach ($potgraders as $t) { + if ($t->id == $user->id) { + continue; // do not send self + } + if (groups_is_member($group->id, $t->id)) { + $graders[$t->id] = $t; + } + } + } + } else { + // user not in group, try to find graders without group + foreach ($potgraders as $t) { + if ($t->id == $user->id) { + continue; // do not send self + } + if (!groups_get_all_groups($this->course->id, $t->id)) { //ugly hack + $graders[$t->id] = $t; + } + } + } + } else { + foreach ($potgraders as $t) { + if ($t->id == $user->id) { + continue; // do not send self + } + $graders[$t->id] = $t; + } + } + return $graders; + } + + /** + * Creates the text content for emails to teachers + * + * @param $info object The info used by the 'emailteachermail' language string + * @return string + */ + function email_teachers_text($info) { + $posttext = format_string($this->course->shortname).' -> '.$this->strassignments.' -> '. + format_string($this->assignment->name)."\n"; + $posttext .= '---------------------------------------------------------------------'."\n"; + $posttext .= get_string("emailteachermail", "assignment", $info)."\n"; + $posttext .= "\n---------------------------------------------------------------------\n"; + return $posttext; + } + + /** + * Creates the html content for emails to teachers + * + * @param $info object The info used by the 'emailteachermailhtml' language string + * @return string + */ + function email_teachers_html($info) { + global $CFG; + $posthtml = '

'. + ''.format_string($this->course->shortname).' ->'. + ''.$this->strassignments.' ->'. + ''.format_string($this->assignment->name).'

'; + $posthtml .= '
'; + $posthtml .= '

'.get_string('emailteachermailhtml', 'assignment', $info).'

'; + $posthtml .= '

'; + return $posthtml; + } + + /** + * Produces a list of links to the files uploaded by a user + * + * @param $userid int optional id of the user. If 0 then $USER->id is used. + * @param $return boolean optional defaults to false. If true the list is returned rather than printed + * @return string optional + */ + function print_user_files($userid=0, $return=false) { + global $CFG, $USER; + + if (!$userid) { + if (!isloggedin()) { + return ''; + } + $userid = $USER->id; + } + + $filearea = $this->file_area_name($userid); + + $output = ''; + + if ($basedir = $this->file_area($userid)) { + if ($files = get_directory_list($basedir)) { + require_once($CFG->libdir.'/filelib.php'); + foreach ($files as $key => $file) { + + $icon = mimeinfo('icon', $file); + $ffurl = get_file_url("$filearea/$file", array('forcedownload'=>1)); + + $output .= ''.$icon.''. + ''.$file.'
'; + } + } + } + + $output = '
'.$output.'
'; + + if ($return) { + return $output; + } + echo $output; + } + + /** + * Count the files uploaded by a given user + * + * @param $userid int The user id + * @return int + */ + function count_user_files($userid) { + global $CFG; + + $filearea = $this->file_area_name($userid); + + if ( is_dir($CFG->dataroot.'/'.$filearea) && $basedir = $this->file_area($userid)) { + if ($files = get_directory_list($basedir)) { + return count($files); + } + } + return 0; + } + + /** + * Creates a directory file name, suitable for make_upload_directory() + * + * @param $userid int The user id + * @return string path to file area + */ + function file_area_name($userid) { + global $CFG; + + return $this->course->id.'/'.$CFG->moddata.'/assignment/'.$this->assignment->id.'/'.$userid; + } + + /** + * Makes an upload directory + * + * @param $userid int The user id + * @return string path to file area. + */ + function file_area($userid) { + return make_upload_directory( $this->file_area_name($userid) ); + } + + /** + * Returns true if the student is allowed to submit + * + * Checks that the assignment has started and, if the option to prevent late + * submissions is set, also checks that the assignment has not yet closed. + * @return boolean + */ + function isopen() { + $time = time(); + if ($this->assignment->preventlate && $this->assignment->timedue) { + return ($this->assignment->timeavailable <= $time && $time <= $this->assignment->timedue); + } else { + return ($this->assignment->timeavailable <= $time); + } + } + + + /** + * Return true if is set description is hidden till available date + * + * This is needed by calendar so that hidden descriptions do not + * come up in upcoming events. + * + * Check that description is hidden till available date + * By default return false + * Assignments types should implement this method if needed + * @return boolen + */ + function description_is_hidden() { + return false; + } + + /** + * Return an outline of the user's interaction with the assignment + * + * The default method prints the grade and timemodified + * @param $user object + * @return object with properties ->info and ->time + */ + function user_outline($user) { + if ($submission = $this->get_submission($user->id)) { + + $result = new object(); + $result->info = get_string('grade').': '.$this->display_grade($submission->grade); + $result->time = $submission->timemodified; + return $result; + } + return NULL; + } + + /** + * Print complete information about the user's interaction with the assignment + * + * @param $user object + */ + function user_complete($user) { + if ($submission = $this->get_submission($user->id)) { + if ($basedir = $this->file_area($user->id)) { + if ($files = get_directory_list($basedir)) { + $countfiles = count($files)." ".get_string("uploadedfiles", "assignment"); + foreach ($files as $file) { + $countfiles .= "; $file"; + } + } + } + + print_simple_box_start(); + echo get_string("lastmodified").": "; + echo userdate($submission->timemodified); + echo $this->display_lateness($submission->timemodified); + + $this->print_user_files($user->id); + + echo '
'; + + if (empty($submission->timemarked)) { + print_string("notgradedyet", "assignment"); + } else { + $this->view_feedback($submission); + } + + print_simple_box_end(); + + } else { + print_string("notsubmittedyet", "assignment"); + } + } + + /** + * Return a string indicating how late a submission is + * + * @param $timesubmitted int + * @return string + */ + function display_lateness($timesubmitted) { + return assignment_display_lateness($timesubmitted, $this->assignment->timedue); + } + + /** + * Empty method stub for all delete actions. + */ + function delete() { + //nothing by default + redirect('view.php?id='.$this->cm->id); + } + + /** + * Empty custom feedback grading form. + */ + function custom_feedbackform($submission, $return=false) { + //nothing by default + return ''; + } + + /** + * Add a get_coursemodule_info function in case any assignment type wants to add 'extra' information + * for the course (see resource). + * + * Given a course_module object, this function returns any "extra" information that may be needed + * when printing this activity in a course listing. See get_array_of_activities() in course/lib.php. + * + * @param $coursemodule object The coursemodule object (record). + * @return object An object on information that the coures will know about (most noticeably, an icon). + * + */ + function get_coursemodule_info($coursemodule) { + return false; + } + + /** + * Plugin cron method - do not use $this here, create new assignment instances if needed. + * @return void + */ + function cron() { + //no plugin cron by default - override if needed + } + + /** + * Reset all submissions + */ + function reset_userdata($data) { + global $CFG; + require_once($CFG->libdir.'/filelib.php'); + + if (!count_records('assignment', 'course', $data->courseid, 'assignmenttype', $this->type)) { + return array(); // no assignments of this type present + } + + $componentstr = get_string('modulenameplural', 'assignment'); + $status = array(); + + $typestr = get_string('type'.$this->type, 'assignment'); + + if (!empty($data->reset_assignment_submissions)) { + $assignmentssql = "SELECT a.id + FROM {$CFG->prefix}assignment a + WHERE a.course={$data->courseid} AND a.assignmenttype='{$this->type}'"; + + delete_records_select('assignment_submissions', "assignment IN ($assignmentssql)"); + + if ($assignments = get_records_sql($assignmentssql)) { + foreach ($assignments as $assignmentid=>$unused) { + fulldelete($CFG->dataroot.'/'.$data->courseid.'/moddata/assignment/'.$assignmentid); + } + } + + $status[] = array('component'=>$componentstr, 'item'=>get_string('deleteallsubmissions','assignment').': '.$typestr, 'error'=>false); + + if (empty($data->reset_gradebook_grades)) { + // remove all grades from gradebook + assignment_reset_gradebook($data->courseid, $this->type); + } + } + + /// updating dates - shift may be negative too + if ($data->timeshift) { + shift_course_mod_dates('assignment', array('timedue', 'timeavailable'), $data->timeshift, $data->courseid); + $status[] = array('component'=>$componentstr, 'item'=>get_string('datechanged').': '.$typestr, 'error'=>false); + } + + return $status; + } +} ////// End of the assignment_base class + + + +/// OTHER STANDARD FUNCTIONS //////////////////////////////////////////////////////// + +/** + * Deletes an assignment instance + * + * This is done by calling the delete_instance() method of the assignment type class + */ +function assignment_delete_instance($id){ + global $CFG; + + if (! $assignment = get_record('assignment', 'id', $id)) { + return false; + } + + // fall back to base class if plugin missing + $classfile = "$CFG->dirroot/mod/assignment/type/$assignment->assignmenttype/assignment.class.php"; + if (file_exists($classfile)) { + require_once($classfile); + $assignmentclass = "assignment_$assignment->assignmenttype"; + + } else { + debugging("Missing assignment plug-in: {$assignment->assignmenttype}. Using base class for deleting instead."); + $assignmentclass = "assignment_base"; + } + + $ass = new $assignmentclass(); + return $ass->delete_instance($assignment); +} + + +/** + * Updates an assignment instance + * + * This is done by calling the update_instance() method of the assignment type class + */ +function assignment_update_instance($assignment){ + global $CFG; + + $assignment->assignmenttype = clean_param($assignment->assignmenttype, PARAM_SAFEDIR); + + require_once("$CFG->dirroot/mod/assignment/type/$assignment->assignmenttype/assignment.class.php"); + $assignmentclass = "assignment_$assignment->assignmenttype"; + $ass = new $assignmentclass(); + return $ass->update_instance($assignment); +} + + +/** + * Adds an assignment instance + * + * This is done by calling the add_instance() method of the assignment type class + */ +function assignment_add_instance($assignment) { + global $CFG; + + $assignment->assignmenttype = clean_param($assignment->assignmenttype, PARAM_SAFEDIR); + + require_once("$CFG->dirroot/mod/assignment/type/$assignment->assignmenttype/assignment.class.php"); + $assignmentclass = "assignment_$assignment->assignmenttype"; + $ass = new $assignmentclass(); + return $ass->add_instance($assignment); +} + + +/** + * Returns an outline of a user interaction with an assignment + * + * This is done by calling the user_outline() method of the assignment type class + */ +function assignment_user_outline($course, $user, $mod, $assignment) { + global $CFG; + + require_once("$CFG->dirroot/mod/assignment/type/$assignment->assignmenttype/assignment.class.php"); + $assignmentclass = "assignment_$assignment->assignmenttype"; + $ass = new $assignmentclass($mod->id, $assignment, $mod, $course); + return $ass->user_outline($user); +} + +/** + * Prints the complete info about a user's interaction with an assignment + * + * This is done by calling the user_complete() method of the assignment type class + */ +function assignment_user_complete($course, $user, $mod, $assignment) { + global $CFG; + + require_once("$CFG->dirroot/mod/assignment/type/$assignment->assignmenttype/assignment.class.php"); + $assignmentclass = "assignment_$assignment->assignmenttype"; + $ass = new $assignmentclass($mod->id, $assignment, $mod, $course); + return $ass->user_complete($user); +} + +/** + * Function to be run periodically according to the moodle cron + * + * Finds all assignment notifications that have yet to be mailed out, and mails them + */ +function assignment_cron () { + + global $CFG, $USER; + + /// first execute all crons in plugins + if ($plugins = get_list_of_plugins('mod/assignment/type')) { + foreach ($plugins as $plugin) { + require_once("$CFG->dirroot/mod/assignment/type/$plugin/assignment.class.php"); + $assignmentclass = "assignment_$plugin"; + $ass = new $assignmentclass(); + $ass->cron(); + } + } + + /// Notices older than 1 day will not be mailed. This is to avoid the problem where + /// cron has not been running for a long time, and then suddenly people are flooded + /// with mail from the past few weeks or months + + $timenow = time(); + $endtime = $timenow - $CFG->maxeditingtime; + $starttime = $endtime - 24 * 3600; /// One day earlier + + if ($submissions = assignment_get_unmailed_submissions($starttime, $endtime)) { + + $realuser = clone($USER); + + foreach ($submissions as $key => $submission) { + if (! set_field("assignment_submissions", "mailed", "1", "id", "$submission->id")) { + echo "Could not update the mailed field for id $submission->id. Not mailed.\n"; + unset($submissions[$key]); + } + } + + $timenow = time(); + + foreach ($submissions as $submission) { + + echo "Processing assignment submission $submission->id\n"; + + if (! $user = get_record("user", "id", "$submission->userid")) { + echo "Could not find user $post->userid\n"; + continue; + } + + if (! $course = get_record("course", "id", "$submission->course")) { + echo "Could not find course $submission->course\n"; + continue; + } + + /// Override the language and timezone of the "current" user, so that + /// mail is customised for the receiver. + $USER = $user; + course_setup($course); + + if (!has_capability('moodle/course:view', get_context_instance(CONTEXT_COURSE, $submission->course), $user->id)) { + echo fullname($user)." not an active participant in " . format_string($course->shortname) . "\n"; + continue; + } + + if (! $teacher = get_record("user", "id", "$submission->teacher")) { + echo "Could not find teacher $submission->teacher\n"; + continue; + } + + if (! $mod = get_coursemodule_from_instance("assignment", $submission->assignment, $course->id)) { + echo "Could not find course module for assignment id $submission->assignment\n"; + continue; + } + + if (! $mod->visible) { /// Hold mail notification for hidden assignments until later + continue; + } + + $strassignments = get_string("modulenameplural", "assignment"); + $strassignment = get_string("modulename", "assignment"); + + $assignmentinfo = new object(); + $assignmentinfo->teacher = fullname($teacher); + $assignmentinfo->assignment = format_string($submission->name,true); + $assignmentinfo->url = "$CFG->wwwroot/mod/assignment/view.php?id=$mod->id"; + + $postsubject = "$course->shortname: $strassignments: ".format_string($submission->name,true); + $posttext = "$course->shortname -> $strassignments -> ".format_string($submission->name,true)."\n"; + $posttext .= "---------------------------------------------------------------------\n"; + $posttext .= get_string("assignmentmail", "assignment", $assignmentinfo)."\n"; + $posttext .= "---------------------------------------------------------------------\n"; + + if ($user->mailformat == 1) { // HTML + $posthtml = "

". + "wwwroot/course/view.php?id=$course->id\">$course->shortname ->". + "wwwroot/mod/assignment/index.php?id=$course->id\">$strassignments ->". + "wwwroot/mod/assignment/view.php?id=$mod->id\">".format_string($submission->name,true)."

"; + $posthtml .= "
"; + $posthtml .= "

".get_string("assignmentmailhtml", "assignment", $assignmentinfo)."

"; + $posthtml .= "

"; + } else { + $posthtml = ""; + } + + if (! email_to_user($user, $teacher, $postsubject, $posttext, $posthtml)) { + echo "Error: assignment cron: Could not send out mail for id $submission->id to user $user->id ($user->email)\n"; + } + } + + $USER = $realuser; + course_setup(SITEID); // reset cron user language, theme and timezone settings + + } + + return true; +} + +/** + * Return grade for given user or all users. + * + * @param int $assignmentid id of assignment + * @param int $userid optional user id, 0 means all users + * @return array array of grades, false if none + */ +function assignment_get_user_grades($assignment, $userid=0) { + global $CFG; + + $user = $userid ? "AND u.id = $userid" : ""; + + $sql = "SELECT u.id, u.id AS userid, s.grade AS rawgrade, s.submissioncomment AS feedback, s.format AS feedbackformat, + s.teacher AS usermodified, s.timemarked AS dategraded, s.timemodified AS datesubmitted + FROM {$CFG->prefix}user u, {$CFG->prefix}assignment_submissions s + WHERE u.id = s.userid AND s.assignment = $assignment->id + $user"; + + return get_records_sql($sql); +} + +/** + * Update grades by firing grade_updated event + * + * @param object $assignment null means all assignments + * @param int $userid specific user only, 0 mean all + */ +function assignment_update_grades($assignment=null, $userid=0, $nullifnone=true) { + global $CFG; + if (!function_exists('grade_update')) { //workaround for buggy PHP versions + require_once($CFG->libdir.'/gradelib.php'); + } + + if ($assignment != null) { + if ($grades = assignment_get_user_grades($assignment, $userid)) { + foreach($grades as $k=>$v) { + if ($v->rawgrade == -1) { + $grades[$k]->rawgrade = null; + } + } + assignment_grade_item_update($assignment, $grades); + } else { + assignment_grade_item_update($assignment); + } + + } else { + $sql = "SELECT a.*, cm.idnumber as cmidnumber, a.course as courseid + FROM {$CFG->prefix}assignment a, {$CFG->prefix}course_modules cm, {$CFG->prefix}modules m + WHERE m.name='assignment' AND m.id=cm.module AND cm.instance=a.id"; + if ($rs = get_recordset_sql($sql)) { + while ($assignment = rs_fetch_next_record($rs)) { + if ($assignment->grade != 0) { + assignment_update_grades($assignment); + } else { + assignment_grade_item_update($assignment); + } + } + rs_close($rs); + } + } +} + +/** + * Create grade item for given assignment + * + * @param object $assignment object with extra cmidnumber + * @param mixed optional array/object of grade(s); 'reset' means reset grades in gradebook + * @return int 0 if ok, error code otherwise + */ +function assignment_grade_item_update($assignment, $grades=NULL) { + global $CFG; + if (!function_exists('grade_update')) { //workaround for buggy PHP versions + require_once($CFG->libdir.'/gradelib.php'); + } + + if (!isset($assignment->courseid)) { + $assignment->courseid = $assignment->course; + } + + $params = array('itemname'=>$assignment->name, 'idnumber'=>$assignment->cmidnumber); + + if ($assignment->grade > 0) { + $params['gradetype'] = GRADE_TYPE_VALUE; + $params['grademax'] = $assignment->grade; + $params['grademin'] = 0; + + } else if ($assignment->grade < 0) { + $params['gradetype'] = GRADE_TYPE_SCALE; + $params['scaleid'] = -$assignment->grade; + + } else { + $params['gradetype'] = GRADE_TYPE_TEXT; // allow text comments only + } + + if ($grades === 'reset') { + $params['reset'] = true; + $grades = NULL; + } + + return grade_update('mod/assignment', $assignment->courseid, 'mod', 'assignment', $assignment->id, 0, $grades, $params); +} + +/** + * Delete grade item for given assignment + * + * @param object $assignment object + * @return object assignment + */ +function assignment_grade_item_delete($assignment) { + global $CFG; + require_once($CFG->libdir.'/gradelib.php'); + + if (!isset($assignment->courseid)) { + $assignment->courseid = $assignment->course; + } + + return grade_update('mod/assignment', $assignment->courseid, 'mod', 'assignment', $assignment->id, 0, NULL, array('deleted'=>1)); +} + +/** + * Returns the users with data in one assignment (students and teachers) + * + * @param $assignmentid int + * @return array of user objects + */ +function assignment_get_participants($assignmentid) { + + global $CFG; + + //Get students + $students = get_records_sql("SELECT DISTINCT u.id, u.id + FROM {$CFG->prefix}user u, + {$CFG->prefix}assignment_submissions a + WHERE a.assignment = '$assignmentid' and + u.id = a.userid"); + //Get teachers + $teachers = get_records_sql("SELECT DISTINCT u.id, u.id + FROM {$CFG->prefix}user u, + {$CFG->prefix}assignment_submissions a + WHERE a.assignment = '$assignmentid' and + u.id = a.teacher"); + + //Add teachers to students + if ($teachers) { + foreach ($teachers as $teacher) { + $students[$teacher->id] = $teacher; + } + } + //Return students array (it contains an array of unique users) + return ($students); +} + +/** + * Checks if a scale is being used by an assignment + * + * This is used by the backup code to decide whether to back up a scale + * @param $assignmentid int + * @param $scaleid int + * @return boolean True if the scale is used by the assignment + */ +function assignment_scale_used($assignmentid, $scaleid) { + + $return = false; + + $rec = get_record('assignment','id',$assignmentid,'grade',-$scaleid); + + if (!empty($rec) && !empty($scaleid)) { + $return = true; + } + + return $return; +} + +/** + * Checks if scale is being used by any instance of assignment + * + * This is used to find out if scale used anywhere + * @param $scaleid int + * @return boolean True if the scale is used by any assignment + */ +function assignment_scale_used_anywhere($scaleid) { + if ($scaleid and record_exists('assignment', 'grade', -$scaleid)) { + return true; + } else { + return false; + } +} + +/** + * Make sure up-to-date events are created for all assignment instances + * + * This standard function will check all instances of this module + * and make sure there are up-to-date events created for each of them. + * If courseid = 0, then every assignment event in the site is checked, else + * only assignment events belonging to the course specified are checked. + * This function is used, in its new format, by restore_refresh_events() + * + * @param $courseid int optional If zero then all assignments for all courses are covered + * @return boolean Always returns true + */ +function assignment_refresh_events($courseid = 0) { + + if ($courseid == 0) { + if (! $assignments = get_records("assignment")) { + return true; + } + } else { + if (! $assignments = get_records("assignment", "course", $courseid)) { + return true; + } + } + $moduleid = get_field('modules', 'id', 'name', 'assignment'); + + foreach ($assignments as $assignment) { + $event = NULL; + $event->name = addslashes($assignment->name); + $event->description = addslashes($assignment->description); + $event->timestart = $assignment->timedue; + + if ($event->id = get_field('event', 'id', 'modulename', 'assignment', 'instance', $assignment->id)) { + update_event($event); + + } else { + $event->courseid = $assignment->course; + $event->groupid = 0; + $event->userid = 0; + $event->modulename = 'assignment'; + $event->instance = $assignment->id; + $event->eventtype = 'due'; + $event->timeduration = 0; + $event->visible = get_field('course_modules', 'visible', 'module', $moduleid, 'instance', $assignment->id); + add_event($event); + } + + } + return true; +} + +/** + * Print recent activity from all assignments in a given course + * + * This is used by the recent activity block + */ +function assignment_print_recent_activity($course, $viewfullnames, $timestart) { + global $CFG, $USER; + + // do not use log table if possible, it may be huge + + if (!$submissions = get_records_sql("SELECT asb.id, asb.timemodified, cm.id AS cmid, asb.userid, + u.firstname, u.lastname, u.email, u.picture + FROM {$CFG->prefix}assignment_submissions asb + JOIN {$CFG->prefix}assignment a ON a.id = asb.assignment + JOIN {$CFG->prefix}course_modules cm ON cm.instance = a.id + JOIN {$CFG->prefix}modules md ON md.id = cm.module + JOIN {$CFG->prefix}user u ON u.id = asb.userid + WHERE asb.timemodified > $timestart AND + a.course = {$course->id} AND + md.name = 'assignment' + ORDER BY asb.timemodified ASC")) { + return false; + } + + $modinfo =& get_fast_modinfo($course); // reference needed because we might load the groups + $show = array(); + $grader = array(); + + foreach($submissions as $submission) { + if (!array_key_exists($submission->cmid, $modinfo->cms)) { + continue; + } + $cm = $modinfo->cms[$submission->cmid]; + if (!$cm->uservisible) { + continue; + } + if ($submission->userid == $USER->id) { + $show[] = $submission; + continue; + } + + // the act of sumbitting of assignment may be considered private - only graders will see it if specified + if (empty($CFG->assignment_showrecentsubmissions)) { + if (!array_key_exists($cm->id, $grader)) { + $grader[$cm->id] = has_capability('moodle/grade:viewall', get_context_instance(CONTEXT_MODULE, $cm->id)); + } + if (!$grader[$cm->id]) { + continue; + } + } + + $groupmode = groups_get_activity_groupmode($cm, $course); + + if ($groupmode == SEPARATEGROUPS and !has_capability('moodle/site:accessallgroups', get_context_instance(CONTEXT_MODULE, $cm->id))) { + if (isguestuser()) { + // shortcut - guest user does not belong into any group + continue; + } + + if (is_null($modinfo->groups)) { + $modinfo->groups = groups_get_user_groups($course->id); // load all my groups and cache it in modinfo + } + + // this will be slow - show only users that share group with me in this cm + if (empty($modinfo->groups[$cm->id])) { + continue; + } + $usersgroups = groups_get_all_groups($course->id, $cm->userid, $cm->groupingid); + if (is_array($usersgroups)) { + $usersgroups = array_keys($usersgroups); + $interset = array_intersect($usersgroups, $modinfo->groups[$cm->id]); + if (empty($intersect)) { + continue; + } + } + } + $show[] = $submission; + } + + if (empty($show)) { + return false; + } + + print_headline(get_string('newsubmissions', 'assignment').':'); + + foreach ($show as $submission) { + $cm = $modinfo->cms[$submission->cmid]; + $link = $CFG->wwwroot.'/mod/assignment/view.php?id='.$cm->id; + print_recent_activity_note($submission->timemodified, $submission, $cm->name, $link, false, $viewfullnames); + } + + return true; +} + + +/** + * Returns all assignments since a given time in specified forum. + */ +function assignment_get_recent_mod_activity(&$activities, &$index, $timestart, $courseid, $cmid, $userid=0, $groupid=0) { + + global $CFG, $COURSE, $USER; + + if ($COURSE->id == $courseid) { + $course = $COURSE; + } else { + $course = get_record('course', 'id', $courseid); + } + + $modinfo =& get_fast_modinfo($course); + + $cm = $modinfo->cms[$cmid]; + + if ($userid) { + $userselect = "AND u.id = $userid"; + } else { + $userselect = ""; + } + + if ($groupid) { + $groupselect = "AND gm.groupid = $groupid"; + $groupjoin = "JOIN {$CFG->prefix}groups_members gm ON gm.userid=u.id"; + } else { + $groupselect = ""; + $groupjoin = ""; + } + + if (!$submissions = get_records_sql("SELECT asb.id, asb.timemodified, asb.userid, + u.firstname, u.lastname, u.email, u.picture + FROM {$CFG->prefix}assignment_submissions asb + JOIN {$CFG->prefix}assignment a ON a.id = asb.assignment + JOIN {$CFG->prefix}user u ON u.id = asb.userid + $groupjoin + WHERE asb.timemodified > $timestart AND a.id = $cm->instance + $userselect $groupselect + ORDER BY asb.timemodified ASC")) { + return; + } + + $groupmode = groups_get_activity_groupmode($cm, $course); + $cm_context = get_context_instance(CONTEXT_MODULE, $cm->id); + $grader = has_capability('moodle/grade:viewall', $cm_context); + $accessallgroups = has_capability('moodle/site:accessallgroups', $cm_context); + $viewfullnames = has_capability('moodle/site:viewfullnames', $cm_context); + + if (is_null($modinfo->groups)) { + $modinfo->groups = groups_get_user_groups($course->id); // load all my groups and cache it in modinfo + } + + $show = array(); + + foreach($submissions as $submission) { + if ($submission->userid == $USER->id) { + $show[] = $submission; + continue; + } + // the act of submitting of assignment may be considered private - only graders will see it if specified + if (empty($CFG->assignment_showrecentsubmissions)) { + if (!$grader) { + continue; + } + } + + if ($groupmode == SEPARATEGROUPS and !$accessallgroups) { + if (isguestuser()) { + // shortcut - guest user does not belong into any group + continue; + } + + // this will be slow - show only users that share group with me in this cm + if (empty($modinfo->groups[$cm->id])) { + continue; + } + $usersgroups = groups_get_all_groups($course->id, $cm->userid, $cm->groupingid); + if (is_array($usersgroups)) { + $usersgroups = array_keys($usersgroups); + $interset = array_intersect($usersgroups, $modinfo->groups[$cm->id]); + if (empty($intersect)) { + continue; + } + } + } + $show[] = $submission; + } + + if (empty($show)) { + return; + } + + if ($grader) { + require_once($CFG->libdir.'/gradelib.php'); + $userids = array(); + foreach ($show as $id=>$submission) { + $userids[] = $submission->userid; + + } + $grades = grade_get_grades($courseid, 'mod', 'assignment', $cm->instance, $userids); + } + + $aname = format_string($cm->name,true); + foreach ($show as $submission) { + $tmpactivity = new object(); + + $tmpactivity->type = 'assignment'; + $tmpactivity->cmid = $cm->id; + $tmpactivity->name = $aname; + $tmpactivity->sectionnum = $cm->sectionnum; + $tmpactivity->timestamp = $submission->timemodified; + + if ($grader) { + $tmpactivity->grade = $grades->items[0]->grades[$submission->userid]->str_long_grade; + } + + $tmpactivity->user->userid = $submission->userid; + $tmpactivity->user->fullname = fullname($submission, $viewfullnames); + $tmpactivity->user->picture = $submission->picture; + + $activities[$index++] = $tmpactivity; + } + + return; +} + +/** + * Print recent activity from all assignments in a given course + * + * This is used by course/recent.php + */ +function assignment_print_recent_mod_activity($activity, $courseid, $detail, $modnames) { + global $CFG; + + echo ''; + + echo "
"; + print_user_picture($activity->user->userid, $courseid, $activity->user->picture); + echo ""; + + if ($detail) { + $modname = $modnames[$activity->type]; + echo '
'; + echo "modpixpath/assignment/icon.gif\" ". + "class=\"icon\" alt=\"$modname\">"; + echo "wwwroot/mod/assignment/view.php?id={$activity->cmid}\">{$activity->name}"; + echo '
'; + } + + if (isset($activity->grade)) { + echo '
'; + echo get_string('grade').': '; + echo $activity->grade; + echo '
'; + } + + echo ''; + + echo "
"; +} + +/// GENERIC SQL FUNCTIONS + +/** + * Fetch info from logs + * + * @param $log object with properties ->info (the assignment id) and ->userid + * @return array with assignment name and user firstname and lastname + */ +function assignment_log_info($log) { + global $CFG; + return get_record_sql("SELECT a.name, u.firstname, u.lastname + FROM {$CFG->prefix}assignment a, + {$CFG->prefix}user u + WHERE a.id = '$log->info' + AND u.id = '$log->userid'"); +} + +/** + * Return list of marked submissions that have not been mailed out for currently enrolled students + * + * @return array + */ +function assignment_get_unmailed_submissions($starttime, $endtime) { + + global $CFG; + + return get_records_sql("SELECT s.*, a.course, a.name + FROM {$CFG->prefix}assignment_submissions s, + {$CFG->prefix}assignment a + WHERE s.mailed = 0 + AND s.timemarked <= $endtime + AND s.timemarked >= $starttime + AND s.assignment = a.id"); + + /* return get_records_sql("SELECT s.*, a.course, a.name + FROM {$CFG->prefix}assignment_submissions s, + {$CFG->prefix}assignment a, + {$CFG->prefix}user_students us + WHERE s.mailed = 0 + AND s.timemarked <= $endtime + AND s.timemarked >= $starttime + AND s.assignment = a.id + AND s.userid = us.userid + AND a.course = us.course"); + */ +} + +/** + * Counts all real assignment submissions by ENROLLED students (not empty ones) + * + * There are also assignment type methods count_real_submissions() wich in the default + * implementation simply call this function. + * @param $groupid int optional If nonzero then count is restricted to this group + * @return int The number of submissions + */ +function assignment_count_real_submissions($cm, $groupid=0) { + global $CFG; + + $context = get_context_instance(CONTEXT_MODULE, $cm->id); + + // this is all the users with this capability set, in this context or higher + if ($users = get_users_by_capability($context, 'mod/assignment:submit', 'u.id', '', '', '', $groupid, '', false)) { + $users = array_keys($users); + } + + // if groupmembersonly used, remove users who are not in any group + if ($users and !empty($CFG->enablegroupings) and $cm->groupmembersonly) { + if ($groupingusers = groups_get_grouping_members($cm->groupingid, 'u.id', 'u.id')) { + $users = array_intersect($users, array_keys($groupingusers)); + } + } + + if (empty($users)) { + return 0; + } + + $userlists = implode(',', $users); + + return count_records_sql("SELECT COUNT('x') + FROM {$CFG->prefix}assignment_submissions + WHERE assignment = $cm->instance AND + timemodified > 0 AND + userid IN ($userlists)"); +} + + +/** + * Return all assignment submissions by ENROLLED students (even empty) + * + * There are also assignment type methods get_submissions() wich in the default + * implementation simply call this function. + * @param $sort string optional field names for the ORDER BY in the sql query + * @param $dir string optional specifying the sort direction, defaults to DESC + * @return array The submission objects indexed by id + */ +function assignment_get_all_submissions($assignment, $sort="", $dir="DESC") { +/// Return all assignment submissions by ENROLLED students (even empty) + global $CFG; + + if ($sort == "lastname" or $sort == "firstname") { + $sort = "u.$sort $dir"; + } else if (empty($sort)) { + $sort = "a.timemodified DESC"; + } else { + $sort = "a.$sort $dir"; + } + + /* not sure this is needed at all since assignmenet already has a course define, so this join? + $select = "s.course = '$assignment->course' AND"; + if ($assignment->course == SITEID) { + $select = ''; + }*/ + + return get_records_sql("SELECT a.* + FROM {$CFG->prefix}assignment_submissions a, + {$CFG->prefix}user u + WHERE u.id = a.userid + AND a.assignment = '$assignment->id' + ORDER BY $sort"); + + /* return get_records_sql("SELECT a.* + FROM {$CFG->prefix}assignment_submissions a, + {$CFG->prefix}user_students s, + {$CFG->prefix}user u + WHERE a.userid = s.userid + AND u.id = a.userid + AND $select a.assignment = '$assignment->id' + ORDER BY $sort"); + */ +} + +/** + * Add a get_coursemodule_info function in case any assignment type wants to add 'extra' information + * for the course (see resource). + * + * Given a course_module object, this function returns any "extra" information that may be needed + * when printing this activity in a course listing. See get_array_of_activities() in course/lib.php. + * + * @param $coursemodule object The coursemodule object (record). + * @return object An object on information that the coures will know about (most noticeably, an icon). + * + */ +function assignment_get_coursemodule_info($coursemodule) { + global $CFG; + + if (! $assignment = get_record('assignment', 'id', $coursemodule->instance, '', '', '', '', 'id, assignmenttype, name')) { + return false; + } + + $libfile = "$CFG->dirroot/mod/assignment/type/$assignment->assignmenttype/assignment.class.php"; + + if (file_exists($libfile)) { + require_once($libfile); + $assignmentclass = "assignment_$assignment->assignmenttype"; + $ass = new $assignmentclass('staticonly'); + if ($result = $ass->get_coursemodule_info($coursemodule)) { + return $result; + } else { + $info = new object(); + $info->name = $assignment->name; + return $info; + } + + } else { + debugging('Incorrect assignment type: '.$assignment->assignmenttype); + return false; + } +} + + + +/// OTHER GENERAL FUNCTIONS FOR ASSIGNMENTS /////////////////////////////////////// + +/** + * Returns an array of installed assignment types indexed and sorted by name + * + * @return array The index is the name of the assignment type, the value its full name from the language strings + */ +function assignment_types() { + $types = array(); + $names = get_list_of_plugins('mod/assignment/type'); + foreach ($names as $name) { + $types[$name] = get_string('type'.$name, 'assignment'); + } + asort($types); + return $types; +} + +/** + * Executes upgrade scripts for assignment types when necessary + */ +function assignment_upgrade_submodules() { + + global $CFG; + +/// Install/upgrade assignment types (it uses, simply, the standard plugin architecture) + upgrade_plugins('assignment_type', 'mod/assignment/type', "$CFG->wwwroot/$CFG->admin/index.php"); + +} + +function assignment_print_overview($courses, &$htmlarray) { + + global $USER, $CFG; + + if (empty($courses) || !is_array($courses) || count($courses) == 0) { + return array(); + } + + if (!$assignments = get_all_instances_in_courses('assignment',$courses)) { + return; + } + + $assignmentids = array(); + + // Do assignment_base::isopen() here without loading the whole thing for speed + foreach ($assignments as $key => $assignment) { + $time = time(); + if ($assignment->timedue) { + if ($assignment->preventlate) { + $isopen = ($assignment->timeavailable <= $time && $time <= $assignment->timedue); + } else { + $isopen = ($assignment->timeavailable <= $time); + } + } + if (empty($isopen) || empty($assignment->timedue)) { + unset($assignments[$key]); + }else{ + $assignmentids[] = $assignment->id; + } + } + + if(empty($assignmentids)){ + // no assigments to look at - we're done + return true; + } + + $strduedate = get_string('duedate', 'assignment'); + $strduedateno = get_string('duedateno', 'assignment'); + $strgraded = get_string('graded', 'assignment'); + $strnotgradedyet = get_string('notgradedyet', 'assignment'); + $strnotsubmittedyet = get_string('notsubmittedyet', 'assignment'); + $strsubmitted = get_string('submitted', 'assignment'); + $strassignment = get_string('modulename', 'assignment'); + $strreviewed = get_string('reviewed','assignment'); + + + // NOTE: we do all possible database work here *outside* of the loop to ensure this scales + + // build up and array of unmarked submissions indexed by assigment id/ userid + // for use where the user has grading rights on assigment + $rs = get_recordset_sql("SELECT id, assignment, userid + FROM {$CFG->prefix}assignment_submissions + WHERE teacher = 0 AND timemarked = 0 + AND assignment IN (". implode(',', $assignmentids).")"); + + $unmarkedsubmissions = array(); + while ($ra = rs_fetch_next_record($rs)) { + $unmarkedsubmissions[$ra->assignment][$ra->userid] = $ra->id; + } + rs_close($rs); + + + // get all user submissions, indexed by assigment id + $mysubmissions = get_records_sql("SELECT assignment, timemarked, teacher, grade + FROM {$CFG->prefix}assignment_submissions + WHERE userid = {$USER->id} AND + assignment IN (".implode(',', $assignmentids).")"); + + foreach ($assignments as $assignment) { + $str = '
'; + if ($assignment->timedue) { + $str .= '
'.$strduedate.': '.userdate($assignment->timedue).'
'; + } else { + $str .= '
'.$strduedateno.'
'; + } + $context = get_context_instance(CONTEXT_MODULE, $assignment->coursemodule); + if (has_capability('mod/assignment:grade', $context)) { + + // count how many people can submit + $submissions = 0; // init + if ($students = get_users_by_capability($context, 'mod/assignment:submit', 'u.id', '', '', '', 0, '', false)) { + foreach($students as $student){ + if(isset($unmarkedsubmissions[$assignment->id][$student->id])){ + $submissions++; + } + } + } + + if ($submissions) { + $str .= get_string('submissionsnotgraded', 'assignment', $submissions); + } + } else { + if(isset($mysubmissions[$assignment->id])){ + + $submission = $mysubmissions[$assignment->id]; + + if ($submission->teacher == 0 && $submission->timemarked == 0) { + $str .= $strsubmitted . ', ' . $strnotgradedyet; + } else if ($submission->grade <= 0) { + $str .= $strsubmitted . ', ' . $strreviewed; + } else { + $str .= $strsubmitted . ', ' . $strgraded; + } + } else { + $str .= $strnotsubmittedyet . ' ' . assignment_display_lateness(time(), $assignment->timedue); + } + } + $str .= '
'; + if (empty($htmlarray[$assignment->course]['assignment'])) { + $htmlarray[$assignment->course]['assignment'] = $str; + } else { + $htmlarray[$assignment->course]['assignment'] .= $str; + } + } +} + +function assignment_display_lateness($timesubmitted, $timedue) { + if (!$timedue) { + return ''; + } + $time = $timedue - $timesubmitted; + if ($time < 0) { + $timetext = get_string('late', 'assignment', format_time($time)); + return ' ('.$timetext.')'; + } else { + $timetext = get_string('early', 'assignment', format_time($time)); + return ' ('.$timetext.')'; + } +} + +function assignment_get_view_actions() { + return array('view'); +} + +function assignment_get_post_actions() { + return array('upload'); +} + +function assignment_get_types() { + global $CFG; + $types = array(); + + $type = new object(); + $type->modclass = MOD_CLASS_ACTIVITY; + $type->type = "assignment_group_start"; + $type->typestr = '--'.get_string('modulenameplural', 'assignment'); + $types[] = $type; + + $standardassignments = array('upload','online','uploadsingle','offline'); + foreach ($standardassignments as $assignmenttype) { + $type = new object(); + $type->modclass = MOD_CLASS_ACTIVITY; + $type->type = "assignment&type=$assignmenttype"; + $type->typestr = get_string("type$assignmenttype", 'assignment'); + $types[] = $type; + } + + /// Drop-in extra assignment types + $assignmenttypes = get_list_of_plugins('mod/assignment/type'); + foreach ($assignmenttypes as $assignmenttype) { + if (!empty($CFG->{'assignment_hide_'.$assignmenttype})) { // Not wanted + continue; + } + if (!in_array($assignmenttype, $standardassignments)) { + $type = new object(); + $type->modclass = MOD_CLASS_ACTIVITY; + $type->type = "assignment&type=$assignmenttype"; + $type->typestr = get_string("type$assignmenttype", 'assignment'); + $types[] = $type; + } + } + + $type = new object(); + $type->modclass = MOD_CLASS_ACTIVITY; + $type->type = "assignment_group_end"; + $type->typestr = '--'; + $types[] = $type; + + return $types; +} + +/** + * Removes all grades from gradebook + * @param int $courseid + * @param string optional type + */ +function assignment_reset_gradebook($courseid, $type='') { + global $CFG; + + $type = $type ? "AND a.assignmenttype='$type'" : ''; + + $sql = "SELECT a.*, cm.idnumber as cmidnumber, a.course as courseid + FROM {$CFG->prefix}assignment a, {$CFG->prefix}course_modules cm, {$CFG->prefix}modules m + WHERE m.name='assignment' AND m.id=cm.module AND cm.instance=a.id AND a.course=$courseid $type"; + + if ($assignments = get_records_sql($sql)) { + foreach ($assignments as $assignment) { + assignment_grade_item_update($assignment, 'reset'); + } + } +} + +/** + * This function is used by the reset_course_userdata function in moodlelib. + * This function will remove all posts from the specified assignment + * and clean up any related data. + * @param $data the data submitted from the reset course. + * @return array status array + */ +function assignment_reset_userdata($data) { + global $CFG; + + $status = array(); + + foreach (get_list_of_plugins('mod/assignment/type') as $type) { + require_once("$CFG->dirroot/mod/assignment/type/$type/assignment.class.php"); + $assignmentclass = "assignment_$type"; + $ass = new $assignmentclass(); + $status = array_merge($status, $ass->reset_userdata($data)); + } + + return $status; +} + +/** + * Implementation of the function for printing the form elements that control + * whether the course reset functionality affects the assignment. + * @param $mform form passed by reference + */ +function assignment_reset_course_form_definition(&$mform) { + $mform->addElement('header', 'assignmentheader', get_string('modulenameplural', 'assignment')); + $mform->addElement('advcheckbox', 'reset_assignment_submissions', get_string('deleteallsubmissions','assignment')); +} + +/** + * Course reset form defaults. + */ +function assignment_reset_course_form_defaults($course) { + return array('reset_assignment_submissions'=>1); +} + +/** + * Returns all other caps used in module + */ +function assignment_get_extra_capabilities() { + return array('moodle/site:accessallgroups', 'moodle/site:viewfullnames'); +} + +?> diff --git a/Moodle/mod/print/log.txt b/Moodle/mod/print/log.txt new file mode 100755 index 0000000..85c4b69 --- /dev/null +++ b/Moodle/mod/print/log.txt @@ -0,0 +1,47 @@ +Jul 14 05:29:13 submissions.php Host localhost:631 user PHP-SERVER : printing job http://localhost.localdomain:631/jobs/7: successfull-ok +Jul 14 05:38:00 submissions.php Host localhost:631 user iwikiwi@localhost : printing job http://localhost.localdomain:631/jobs/8: successfull-ok +Jul 14 05:40:18 submissions.php Host localhost:631 user iwikiwi@localhost : printing job http://localhost.localdomain:631/jobs/9: successfull-ok +Jul 14 06:20:21 submissions.php Host localhost:631 user iwikiwi@localhost : printing job http://localhost.localdomain:631/jobs/10: successfull-ok +Jul 14 06:22:54 submissions.php Host localhost:631 user iwikiwi@localhost : printing job http://localhost.localdomain:631/jobs/11: successfull-ok +Jul 14 06:23:51 submissions.php Host localhost:631 user iwikiwi@localhost : printing job http://localhost.localdomain:631/jobs/12: successfull-ok +Jul 14 06:23:56 submissions.php Host localhost:631 user iwikiwi@localhost : printing job http://localhost.localdomain:631/jobs/13: successfull-ok +Jul 14 06:45:47 submissions.php Host localhost:631 user iwikiwi@localhost : printing job http://localhost.localdomain:631/jobs/14: successfull-ok +Jul 14 06:48:14 submissions.php Host localhost:631 user iwikiwi@localhost : printing job http://localhost.localdomain:631/jobs/15: successfull-ok +Jul 14 06:59:20 submissions.php Host localhost:631 user iwikiwi@localhost : printing job http://localhost.localdomain:631/jobs/16: successfull-ok +Jul 14 07:01:33 submissions.php Host localhost:631 user PHP-SERVER : printing job http://localhost.localdomain:631/jobs/17: successfull-ok +Jul 14 07:03:13 submissions.php Host localhost:631 user PHP-SERVER : printing job http://localhost.localdomain:631/jobs/18: successfull-ok +Jul 14 07:03:43 submissions.php Host localhost:631 user PHP-SERVER : printing job http://localhost.localdomain:631/jobs/19: successfull-ok +Jul 14 07:07:53 submissions.php Host localhost:631 user PHP-SERVER : printing job http://localhost.localdomain:631/jobs/20: successfull-ok +Jul 14 07:17:46 submissions.php Host localhost:631 user PHP-SERVER : printing job http://localhost.localdomain:631/jobs/21: successfull-ok +Jul 14 07:27:07 submissions.php Host localhost:631 user PHP-SERVER : printing job http://localhost.localdomain:631/jobs/22: successfull-ok +Jul 14 12:56:36 submissions.php Host localhost:631 user PHP-SERVER : printing job http://localhost.localdomain:631/jobs/23: successfull-ok +Jul 14 12:59:01 submissions.php Host localhost:631 user PHP-SERVER : printing job http://localhost.localdomain:631/jobs/24: successfull-ok +Jul 14 14:36:15 submissions.php Host localhost:631 user PHP-SERVER : printing job http://localhost.localdomain:631/jobs/25: successfull-ok +Jul 14 14:36:20 submissions.php Host localhost:631 user PHP-SERVER : printing job http://localhost.localdomain:631/jobs/26: successfull-ok +Jul 14 14:59:51 submissions.php Host localhost:631 user PHP-SERVER : printing job http://localhost.localdomain:631/jobs/27: successfull-ok +Jul 14 15:02:17 submissions.php Host localhost:631 user PHP-SERVER : printing job http://localhost.localdomain:631/jobs/28: successfull-ok +Jul 14 15:02:50 submissions.php Host localhost:631 user PHP-SERVER : printing job http://localhost.localdomain:631/jobs/29: successfull-ok +Jul 14 15:03:14 submissions.php Host localhost:631 user PHP-SERVER : printing job http://localhost.localdomain:631/jobs/30: successfull-ok +Jul 14 15:03:38 submissions.php Host localhost:631 user PHP-SERVER : printing job http://localhost.localdomain:631/jobs/31: successfull-ok +Jul 14 15:03:41 submissions.php Host localhost:631 user PHP-SERVER : printing job http://localhost.localdomain:631/jobs/32: successfull-ok +Jul 14 15:03:43 submissions.php Host localhost:631 user PHP-SERVER : printing job http://localhost.localdomain:631/jobs/33: successfull-ok +Jul 14 15:03:46 submissions.php Host localhost:631 user PHP-SERVER : printing job http://localhost.localdomain:631/jobs/34: successfull-ok +Jul 14 15:07:10 submissions.php Host localhost:631 user PHP-SERVER : printing job http://localhost.localdomain:631/jobs/35: successfull-ok +Jul 14 15:07:42 submissions.php Host localhost:631 user PHP-SERVER : printing job http://localhost.localdomain:631/jobs/36: successfull-ok +Jul 14 15:14:16 submissions.php Host localhost:631 user PHP-SERVER : printing job http://localhost.localdomain:631/jobs/37: successfull-ok +Jul 14 19:30:03 submissions.php Host localhost:631 user PHP-SERVER : printing job http://localhost.localdomain:631/jobs/38: successfull-ok +Jul 14 19:51:32 submissions.php Host localhost:631 user PHP-SERVER : printing job http://localhost.localdomain:631/jobs/39: successfull-ok +Jul 29 21:09:56 submissions.php Host localhost:631 user PHP-SERVER : printing job http://localhost.localdomain:631/jobs/83: successfull-ok +Jul 30 14:06:29 submissions.php Host localhost:631 user PHP-SERVER : printing job http://localhost.localdomain:631/jobs/84: successfull-ok +Jul 30 14:23:06 submissions.php Host localhost:631 user PHP-SERVER : printing job http://localhost.localdomain:631/jobs/85: successfull-ok +Jul 30 14:26:06 submissions.php Host localhost:631 user PHP-SERVER : printing job http://localhost.localdomain:631/jobs/86: successfull-ok +Jul 31 00:22:54 submissions.php Host localhost:631 user PHP-SERVER : printing job http://localhost.localdomain:631/jobs/87: successfull-ok +Jul 31 03:46:42 submissions.php Host localhost:631 user PHP-SERVER : printing job http://localhost.localdomain:631/jobs/88: successfull-ok +Jul 31 03:47:52 submissions.php Host localhost:631 user PHP-SERVER : printing job http://localhost.localdomain:631/jobs/89: successfull-ok +Jul 31 03:48:15 submissions.php Host localhost:631 user PHP-SERVER : printing job http://localhost.localdomain:631/jobs/90: successfull-ok +Jul 31 03:55:34 submissions.php Host localhost:631 user PHP-SERVER : printing job http://localhost.localdomain:631/jobs/91: successfull-ok +Jul 31 04:02:54 submissions.php Host localhost:631 user PHP-SERVER : printing job http://localhost.localdomain:631/jobs/92: successfull-ok +Jul 31 04:04:01 submissions.php Host localhost:631 user PHP-SERVER : printing job http://localhost.localdomain:631/jobs/93: successfull-ok +Jul 31 05:24:19 submissions.php Host localhost:631 user PHP-SERVER : printing job http://localhost.localdomain:631/jobs/94: successfull-ok +Jul 31 05:26:26 submissions.php Host localhost:631 user PHP-SERVER : printing job http://localhost.localdomain:631/jobs/95: successfull-ok +Jul 31 05:28:31 submissions.php Host localhost:631 user PHP-SERVER : printing job http://localhost.localdomain:631/jobs/96: successfull-ok diff --git a/Moodle/mod/print/mod_form.php b/Moodle/mod/print/mod_form.php new file mode 100755 index 0000000..ce519d8 --- /dev/null +++ b/Moodle/mod/print/mod_form.php @@ -0,0 +1,52 @@ +dirroot.'/course/moodleform_mod.php'); + +class mod_print_mod_form extends moodleform_mod { + + function definition() { + global $CFG; + $mform =& $this->_form; + + + require_once($CFG->dirroot.'/mod/print/lib.php'); + $assignmentclass = 'print_base'; + $assignmentinstance = new $assignmentclass(); + +//------------------------------------------------------------------------------- + $mform->addElement('header', 'general', get_string('general', 'form')); + + $mform->addElement('text', 'name', get_string('assignmentname', 'assignment'), array('size'=>'64')); + if (!empty($CFG->formatstringstriptags)) { + $mform->setType('name', PARAM_TEXT); + } else { + $mform->setType('name', PARAM_CLEAN); + } + $mform->addRule('name', null, 'required', null, 'client'); + + $mform->addElement('htmleditor', 'description', get_string('description', 'assignment')); + $mform->setType('description', PARAM_RAW); + $mform->setHelpButton('description', array('writing', 'questions', 'richtext'), false, 'editorhelpbutton'); + $mform->addRule('description', get_string('required'), 'required', null, 'client'); + + + $mform->addElement('date_time_selector', 'timeavailable', get_string('availabledate', 'assignment'), array('optional'=>true)); + $mform->setDefault('timeavailable', time()); + + $ynoptions = array( 0 => get_string('no'), 1 => get_string('yes')); + + $mform->addElement('header', 'typedesc', get_string('typeupload','assignment')); + $assignmentinstance->setup_elements($mform); + + $features = new stdClass; + $features->groups = true; + $features->groupings = true; + $features->groupmembersonly = true; + $this->standard_coursemodule_elements($features); + + $this->add_action_buttons(); + } + + + +} +?> \ No newline at end of file diff --git a/Moodle/mod/print/print_xmlrpc.php b/Moodle/mod/print/print_xmlrpc.php new file mode 100755 index 0000000..63df086 --- /dev/null +++ b/Moodle/mod/print/print_xmlrpc.php @@ -0,0 +1,133 @@ +loginpage_hook(); + + error_log("require login done", 0); + #$userrecord = get_record('user', 'username', $username); + #$userid = $userrecord->id; + $id = 2; + if ($id) { + if (! $cm = get_coursemodule_from_id('print', $id)) { + error("Course Module ID was incorrect"); + } + + if (! $assignment = get_record("print", "id", $cm->instance)) { + error("assignment ID was incorrect"); + } + + if (! $course = get_record("course", "id", $assignment->course)) { + error("Course is misconfigured"); + } + } else { + if (!$assignment = get_record("print", "id", $a)) { + error("Course module is incorrect"); + } + if (! $course = get_record("course", "id", $assignment->course)) { + error("Course is misconfigured"); + } + if (! $cm = get_coursemodule_from_instance("print", $assignment->id, $course->id)) { + error("Course Module ID was incorrect"); + } + } + + + + + $assignmentinstance = new print_base($cm->id, $assignment, $cm, $course); + $filearea = $assignmentinstance->file_area_name($USER->id); + + + $handle = fopen($CFG->dataroot."/".$filearea."/".$title.".pdf", "wb"); + fwrite($handle, $file->scalar); + fclose($handle); + $fpath = $CFG->dataroot."/".$filearea."/".$title.".pdf"; + + $assignmentinstance->upload_xmlrpc($fpath, $userid, $title, $assignment);// Display or process the submissions + return 1; +} +function send_func($method_name, $params, $app_data) { + $file = $params[0]; + $title = $params[1]; + actual_func($file, $title); + return 1; +} + +function greeting_func($method_name, $params, $app_data) +{ + $name = $params[0]; + return "Hello, $name. How are you today?"; +} + +/* + * This creates a server and sets a handle for the + * server in the variable $xmlrpc_server + */ +$xmlrpc_server = xmlrpc_server_create(); + +/* + * xmlrpc_server_register_method() registers a PHP + * function as an XML-RPC method. It takes three + * parameters: + * The first is the handle of a server created with + * xmlrpc_server_create(), the second is the name to + * register the server under (this is what needs to + * be in the of a request for this + * method), and the third is the name of the PHP + * function to register. + */ + +xmlrpc_server_register_method($xmlrpc_server, "send_func", "send_func"); +xmlrpc_server_register_method($xmlrpc_server, "greeting_func", "greeting_func"); + +/* + * When an XML-RPC request is sent to this script, it + * can be found in the raw post data. + */ +$request_xml = $HTTP_RAW_POST_DATA; + +/* + * The xmlrpc_server_call_method() sends a request to + * the server and returns the response XML. In this case, + * it sends the raw post data we got before. It requires + * 3 arguments: + * The first is the handle of a server created with + * xmlrpc_server_create(), the second is a string containing + * an XML-RPC request, and the third is for application data. + * Whatever is passed into the third parameter of this function + * is passed as the third paramater of the PHP function that the + * request is asking for. + */ +$response = xmlrpc_server_call_method($xmlrpc_server, $request_xml, ''); + +// Now we print the response for the client to read. +print $response; + +/* + * This method frees the resources for the server specified + * It takes one argument, a handle of a server created with + * xmlrpc_server_create(). + */ +xmlrpc_server_destroy($xmlrpc_server); +?> diff --git a/Moodle/mod/print/styles.php b/Moodle/mod/print/styles.php new file mode 100755 index 0000000..658e8ae --- /dev/null +++ b/Moodle/mod/print/styles.php @@ -0,0 +1,176 @@ +#mod-print-submissions .feedback .content, +#mod-print-submissions .feedback .topic, +#mod-print-submissions .feedback .picture +{ + padding: 10px; + border-width:1px; + border-style:solid; + border-color:#DDDDDD; +} + +#mod-print-submissions form#options div { + text-align:right; + margin-left:auto; + margin-right:20px; +} + +.mod-print .feedback .files { + float: right; + background-color: #EFEFEF; + padding:5px; +} + +.mod-print .feedback .grade, +.mod-print .feedback .outcome, +.mod-print .feedback .finalgrade { + float: right; +} + +.mod-print .feedback .disabledfeedback { + width: 500px; + height: 250px; +} + +.mod-print .feedback .from { + float: left; +} + +.mod-print .feedback .time { + font-size: 0.8em; +} + +.mod-print .late { + color: red; +} + +.mod-print .files img { + margin-right: 4px; +} + +.mod-print .files a { + white-space:nowrap; +} + +#mod-print-submissions .generaltable .r1 { + background-color: #FFFFFF; +} + +#mod-print-submissions .header .commands { + display: inline; +} + +#mod-print-submissions .s0 { + background: #FFD991; +} + +#mod-print-submissions table.submissions td, +#mod-print-submissions table.submissions th +{ + border-width: 1px; + border-style: solid; + border-color: #DDDDDD; + vertical-align: middle; + padding-left: 5px; + padding-right: 5px; +} + +#mod-print-submissions .submissions .grade { + text-align: right; + font-weight:bold; +} + +#mod-print-submissions .picture { + width: 35px; +} + +#mod-print-submissions .fullname { + text-align: left; +} + +#mod-print-submissions .timemodified, +#mod-print-submissions .timemarked +{ + text-align: left; + font-size: 0.9em; +} + +#mod-print-submissions .status { + text-align: center; +} + +#mod-print-submissions .submissions .outcome, +#mod-print-submissions .submissions .finalgrade { + text-align: right; +} + +#mod-print-view #online .singlebutton { + text-align: center; +} + +#mod-print-view #dates { + font-size: 0.8em; + margin-top: 30px; + margin-bottom: 30px; +} + +#mod-print-view #dates .c0{ + text-align:right; + font-weight:bold; +} + +#mod-print-view .feedback { + border-width:1px; + border-style:solid; + border-color:#DDDDDD; + margin-top: 15px; + width: 80%; + margin-left: 10%; + margin-right: 10%; +} + +#mod-print-view .feedback .topic { + padding: 4px; + border-style:solid; + border-width: 0px; + border-bottom-width: 1px; + border-color:#DDDDDD; +} + +#mod-print-view .feedback .fullname { + font-weight: bold; +} + +#mod-print-view .feedback .date { + font-size: 0.8em; +} + +#mod-print-view .feedback .content { + padding: 4px; +} + +#mod-print-view .feedback .grade { + text-align: right; + font-weight:bold; +} + +#mod-print-view .feedback .left { + width: 35px; + padding: 4px; + text-align: center; + vertical-align: top; +} + +#mod-print-submissions .qgprefs #optiontable { + text-align:right; + margin-left:auto; +} + +#mod-print-submissions .fgcontrols { + margin-top: 1em; + text-align:center; +} + +#mod-print-submissions .fgcontrols .fastgbutton{ + margin-top: 0.5em; +} + diff --git a/Moodle/mod/print/submissions.php b/Moodle/mod/print/submissions.php new file mode 100755 index 0000000..f0dd838 --- /dev/null +++ b/Moodle/mod/print/submissions.php @@ -0,0 +1,50 @@ +instance)) { + error("assignment ID was incorrect"); + } + + if (! $course = get_record("course", "id", $assignment->course)) { + error("Course is misconfigured"); + } + } else { + if (!$assignment = get_record("print", "id", $a)) { + error("Course module is incorrect"); + } + if (! $course = get_record("course", "id", $assignment->course)) { + error("Course is misconfigured"); + } + if (! $cm = get_coursemodule_from_instance("print", $assignment->id, $course->id)) { + error("Course Module ID was incorrect"); + } + } + + require_login($course->id, false, $cm); + require_capability('mod/assignment:grade', get_context_instance(CONTEXT_MODULE, $cm->id)); + + +/// Load up the required assignment code + $assignmentclass = 'print_base'; + $assignmentinstance = new $assignmentclass($cm->id, $assignment, $cm, $course); + + $assignmentinstance->submissions('all'); // Display or process the submissions + + + if(isset($_REQUEST['SUBMIT'])) { + $print = $_REQUEST['path']; + print $print; + $assignmentinstance->printit($print); + } +?> diff --git a/Moodle/mod/print/test.php b/Moodle/mod/print/test.php new file mode 100755 index 0000000..5556f42 --- /dev/null +++ b/Moodle/mod/print/test.php @@ -0,0 +1,56 @@ +instance)) { + error("assignment ID was incorrect"); + } + + if (! $course = get_record("course", "id", $assignment->course)) { + error("Course is misconfigured"); + } + } else { + if (!$assignment = get_record("print", "id", $a)) { + error("Course module is incorrect"); + } + if (! $course = get_record("course", "id", $assignment->course)) { + error("Course is misconfigured"); + } + if (! $cm = get_coursemodule_from_instance("print", $assignment->id, $course->id)) { + error("Course Module ID was incorrect"); + } + } + + + + $assignmentinstance = new print_base($cm->id, $assignment, $cm, $course); + $filearea = $assignmentinstance->file_area_name($userid); + print $filearea; + + + $handle = fopen($CFG->dataroot."/".$filearea."/".$title.".pdf", "wb"); + fwrite($handle, $file->scalar); + fclose($handle); + $fpath = $CFG->dataroot."/".$filearea."/".$title.".pdf"; + + $assignmentinstance->upload_xmlrpc($fpath, $userid, $title, $id);// Display or process the submissions + return 1; + +} +$file = new object(); +$file->scalar = 'blablabla'; +print(actual_func($file,3,'Test')); +?> \ No newline at end of file diff --git a/Moodle/mod/print/upload.php b/Moodle/mod/print/upload.php new file mode 100755 index 0000000..9b6287b --- /dev/null +++ b/Moodle/mod/print/upload.php @@ -0,0 +1,41 @@ +instance)) { + error("assignment ID was incorrect"); + } + + if (! $course = get_record("course", "id", $assignment->course)) { + error("Course is misconfigured"); + } + } else { + if (!$assignment = get_record("print", "id", $aid)) { + error("Course module is incorrect"); + } + if (! $course = get_record("course", "id", $assignment->course)) { + error("Course is misconfigured"); + } + if (! $cm = get_coursemodule_from_instance("print", $assignment->id, $course->id)) { + error("Course Module ID was incorrect"); + } + } + + require_login($course->id, false, $cm); + +/// Load up the required assignment code + $printclass = 'print_base'; + $assignmentinstance = new $printclass($cm->id, $assignment, $cm, $course); + + $assignmentinstance->upload(); // Upload files + +?> diff --git a/Moodle/mod/print/version.php b/Moodle/mod/print/version.php new file mode 100755 index 0000000..572c891 --- /dev/null +++ b/Moodle/mod/print/version.php @@ -0,0 +1,15 @@ + + * @version $Id: version.php,v 1.5.2.2 2009/03/19 12:23:11 mudrd8mz Exp $ + * @package mod/print + */ + +$module->version = 2007040205; // The current module version (Date: YYYYMMDDXX) +$module->cron = 0; // Period for cron to check this module (secs) + +?> diff --git a/Moodle/mod/print/view.php b/Moodle/mod/print/view.php new file mode 100755 index 0000000..cbef0ed --- /dev/null +++ b/Moodle/mod/print/view.php @@ -0,0 +1,41 @@ +instance)) { + error("assignment ID was incorrect"); + } + + if (! $course = get_record("course", "id", $assignment->course)) { + error("Course is misconfigured"); + } + } else { + if (!$assignment = get_record("print", $id, $aid)) { + error("Course module is incorrect"); + } + if (! $course = get_record("course", "id", $assignment->course)) { + error("Course is misconfigured"); + } + if (! $cm = get_coursemodule_from_instance("print", $assignment->id, $course->id)) { + error("Course Module ID was incorrect"); + } + } + + require_login($course, true, $cm); + + #require_once ("$CFG->dirroot/mod/print/lib.php"); + $assignmentclass = 'print_base'; + $assignmentinstance = new $assignmentclass($cm->id, $assignment, $cm, $course); + + $assignmentinstance->view1(); // Actually display the assignment! + +?> \ No newline at end of file diff --git a/activity/activity-read.svg b/activity/activity-read.svg index a49ef84..a49ef84 100644..100755 --- a/activity/activity-read.svg +++ b/activity/activity-read.svg diff --git a/activity/activity.info b/activity/activity.info index 3546e76..3546e76 100644..100755 --- a/activity/activity.info +++ b/activity/activity.info diff --git a/activity/gnome-pdf.svg b/activity/gnome-pdf.svg index af6390c..af6390c 100644..100755 --- a/activity/gnome-pdf.svg +++ b/activity/gnome-pdf.svg diff --git a/activity/ooo_printeradmin.svg b/activity/ooo_printeradmin.svg index 8f6b9fd..8f6b9fd 100644..100755 --- a/activity/ooo_printeradmin.svg +++ b/activity/ooo_printeradmin.svg diff --git a/cookiemagic.py b/cookiemagic.py new file mode 100644 index 0000000..de1b024 --- /dev/null +++ b/cookiemagic.py @@ -0,0 +1,57 @@ +import logging +from gettext import gettext as _ +import re + +import sha +import xmlrpclib +import gconf +import os +import base64 +import time +import shutil +import cjson + +from sugar import profile + +class XSCookieTransport(xmlrpclib.Transport): + XSCOOKIE = 'xoid' + def __init__(self, SESSION_ID_STRING='PHPSESSID'): + xmlrpclib.Transport.__init__(self) + self.mycookies=None + self.mysessid=None + self.SESSION_ID_STRING = SESSION_ID_STRING + + def request(self, host, handler, request_body, verbose=0): + # issue XML-RPC request + h = self.make_connection(host) + if verbose: + h.set_debuglevel(1) + self.send_request(h, handler, request_body) + self.send_host(h, host) + h.putheader("Cookie", "%s=%s" % ('xoid',self.__get_xs_cookie()) ) + self.send_content(h, request_body) + errcode, errmsg, headers = h.getreply() + if errcode != 200: + raise xmlrpclib.ProtocolError( + host + handler, + errcode, errmsg, + headers ) + self.verbose = verbose + try: + sock = h._conn.sock + except AttributeError: + sock = None + return self._parse_response(h.getfile(), sock) + + def __get_xs_cookie(self,): + ''' Create a HTTP Cookie to authenticate with the Schoolserver + ''' + # Get Sugar's public key, and use its hash and the colors as the cookie + pubkey = profile.get_profile().pubkey + cookie_data = {'color': profile.get_color().to_string(), + 'pkey_hash': sha.new(pubkey).hexdigest()} + + + cookie = cjson.encode(cookie_data) + + return cookie \ No newline at end of file diff --git a/cupsinfo.txt b/cupsinfo.txt index 90f8d88..90f8d88 100644..100755 --- a/cupsinfo.txt +++ b/cupsinfo.txt diff --git a/po/Read.pot b/po/Read.pot index a969bfd..a969bfd 100644..100755 --- a/po/Read.pot +++ b/po/Read.pot diff --git a/po/af.po b/po/af.po index c48f800..c48f800 100644..100755 --- a/po/af.po +++ b/po/af.po diff --git a/po/am.po b/po/am.po index 328f81a..328f81a 100644..100755 --- a/po/am.po +++ b/po/am.po diff --git a/po/ar.po b/po/ar.po index d2448bb..d2448bb 100644..100755 --- a/po/ar.po +++ b/po/ar.po diff --git a/po/ay.po b/po/ay.po index 328f81a..328f81a 100644..100755 --- a/po/ay.po +++ b/po/ay.po diff --git a/po/bg.po b/po/bg.po index 183e977..183e977 100644..100755 --- a/po/bg.po +++ b/po/bg.po diff --git a/po/bi.po b/po/bi.po index d797e12..d797e12 100644..100755 --- a/po/bi.po +++ b/po/bi.po diff --git a/po/bn.po b/po/bn.po index df04b67..df04b67 100644..100755 --- a/po/bn.po +++ b/po/bn.po diff --git a/po/bn_IN.po b/po/bn_IN.po index a44936b..a44936b 100644..100755 --- a/po/bn_IN.po +++ b/po/bn_IN.po diff --git a/po/ca.po b/po/ca.po index 0724501..0724501 100644..100755 --- a/po/ca.po +++ b/po/ca.po diff --git a/po/cpp.po b/po/cpp.po index d797e12..d797e12 100644..100755 --- a/po/cpp.po +++ b/po/cpp.po diff --git a/po/cs.po b/po/cs.po index d797e12..d797e12 100644..100755 --- a/po/cs.po +++ b/po/cs.po diff --git a/po/de.po b/po/de.po index 7308398..7308398 100644..100755 --- a/po/de.po +++ b/po/de.po diff --git a/po/dz.po b/po/dz.po index cc83252..cc83252 100644..100755 --- a/po/dz.po +++ b/po/dz.po diff --git a/po/el.po b/po/el.po index 89b83d6..89b83d6 100644..100755 --- a/po/el.po +++ b/po/el.po diff --git a/po/en.po b/po/en.po index 328f81a..328f81a 100644..100755 --- a/po/en.po +++ b/po/en.po diff --git a/po/en_US.po b/po/en_US.po index ef3dfbc..ef3dfbc 100644..100755 --- a/po/en_US.po +++ b/po/en_US.po diff --git a/po/es.po b/po/es.po index 182c96d..182c96d 100644..100755 --- a/po/es.po +++ b/po/es.po diff --git a/po/fa.po b/po/fa.po index e7982e7..e7982e7 100644..100755 --- a/po/fa.po +++ b/po/fa.po diff --git a/po/fa_AF.po b/po/fa_AF.po index 6130e4d..6130e4d 100644..100755 --- a/po/fa_AF.po +++ b/po/fa_AF.po diff --git a/po/ff.po b/po/ff.po index a13ecf6..a13ecf6 100644..100755 --- a/po/ff.po +++ b/po/ff.po diff --git a/po/fi.po b/po/fi.po index d797e12..d797e12 100644..100755 --- a/po/fi.po +++ b/po/fi.po diff --git a/po/fr.po b/po/fr.po index 0873484..0873484 100644..100755 --- a/po/fr.po +++ b/po/fr.po diff --git a/po/gu.po b/po/gu.po index d206685..d206685 100644..100755 --- a/po/gu.po +++ b/po/gu.po diff --git a/po/ha.po b/po/ha.po index 328f81a..328f81a 100644..100755 --- a/po/ha.po +++ b/po/ha.po diff --git a/po/he.po b/po/he.po index d797e12..d797e12 100644..100755 --- a/po/he.po +++ b/po/he.po diff --git a/po/hi.po b/po/hi.po index ccc16f1..ccc16f1 100644..100755 --- a/po/hi.po +++ b/po/hi.po diff --git a/po/ht.po b/po/ht.po index 418d73a..418d73a 100644..100755 --- a/po/ht.po +++ b/po/ht.po diff --git a/po/hu.po b/po/hu.po index d797e12..d797e12 100644..100755 --- a/po/hu.po +++ b/po/hu.po diff --git a/po/ig.po b/po/ig.po index 328f81a..328f81a 100644..100755 --- a/po/ig.po +++ b/po/ig.po diff --git a/po/is.po b/po/is.po index 2df1676..2df1676 100644..100755 --- a/po/is.po +++ b/po/is.po diff --git a/po/it.po b/po/it.po index 45185a1..45185a1 100644..100755 --- a/po/it.po +++ b/po/it.po diff --git a/po/ja.po b/po/ja.po index c4581e8..c4581e8 100644..100755 --- a/po/ja.po +++ b/po/ja.po diff --git a/po/km.po b/po/km.po index a9c0ad2..a9c0ad2 100644..100755 --- a/po/km.po +++ b/po/km.po diff --git a/po/ko.po b/po/ko.po index cc83252..cc83252 100644..100755 --- a/po/ko.po +++ b/po/ko.po diff --git a/po/mi.po b/po/mi.po index d797e12..d797e12 100644..100755 --- a/po/mi.po +++ b/po/mi.po diff --git a/po/mk.po b/po/mk.po index 0078541..0078541 100644..100755 --- a/po/mk.po +++ b/po/mk.po diff --git a/po/ml.po b/po/ml.po index cc83252..cc83252 100644..100755 --- a/po/ml.po +++ b/po/ml.po diff --git a/po/mn.po b/po/mn.po index 8d25d59..8d25d59 100644..100755 --- a/po/mn.po +++ b/po/mn.po diff --git a/po/mr.po b/po/mr.po index 848e40e..848e40e 100644..100755 --- a/po/mr.po +++ b/po/mr.po diff --git a/po/ms.po b/po/ms.po index d797e12..d797e12 100644..100755 --- a/po/ms.po +++ b/po/ms.po diff --git a/po/mvo.po b/po/mvo.po index 840ef9f..840ef9f 100644..100755 --- a/po/mvo.po +++ b/po/mvo.po diff --git a/po/nb.po b/po/nb.po index 72145f0..72145f0 100644..100755 --- a/po/nb.po +++ b/po/nb.po diff --git a/po/ne.po b/po/ne.po index 6004aab..6004aab 100644..100755 --- a/po/ne.po +++ b/po/ne.po diff --git a/po/nl.po b/po/nl.po index b620c4d..b620c4d 100644..100755 --- a/po/nl.po +++ b/po/nl.po diff --git a/po/pa.po b/po/pa.po index cc83252..cc83252 100644..100755 --- a/po/pa.po +++ b/po/pa.po diff --git a/po/pap.po b/po/pap.po index 15aa235..15aa235 100644..100755 --- a/po/pap.po +++ b/po/pap.po diff --git a/po/pis.po b/po/pis.po index 840ef9f..840ef9f 100644..100755 --- a/po/pis.po +++ b/po/pis.po diff --git a/po/pl.po b/po/pl.po index 4a00053..4a00053 100644..100755 --- a/po/pl.po +++ b/po/pl.po diff --git a/po/ps.po b/po/ps.po index 32c18fe..32c18fe 100644..100755 --- a/po/ps.po +++ b/po/ps.po diff --git a/po/pseudo.po b/po/pseudo.po index de8db6d..de8db6d 100644..100755 --- a/po/pseudo.po +++ b/po/pseudo.po diff --git a/po/pt.po b/po/pt.po index 8a56f7b..8a56f7b 100644..100755 --- a/po/pt.po +++ b/po/pt.po diff --git a/po/pt_BR.po b/po/pt_BR.po index 099f6b7..099f6b7 100644..100755 --- a/po/pt_BR.po +++ b/po/pt_BR.po diff --git a/po/qu.po b/po/qu.po index 328f81a..328f81a 100644..100755 --- a/po/qu.po +++ b/po/qu.po diff --git a/po/ro.po b/po/ro.po index 1787a44..1787a44 100644..100755 --- a/po/ro.po +++ b/po/ro.po diff --git a/po/ru.po b/po/ru.po index cecfdd5..cecfdd5 100644..100755 --- a/po/ru.po +++ b/po/ru.po diff --git a/po/rw.po b/po/rw.po index 8ae8968..8ae8968 100644..100755 --- a/po/rw.po +++ b/po/rw.po diff --git a/po/sd.po b/po/sd.po index 5c1e346..5c1e346 100644..100755 --- a/po/sd.po +++ b/po/sd.po diff --git a/po/si.po b/po/si.po index 2cf1ab3..2cf1ab3 100644..100755 --- a/po/si.po +++ b/po/si.po diff --git a/po/sk.po b/po/sk.po index d797e12..d797e12 100644..100755 --- a/po/sk.po +++ b/po/sk.po diff --git a/po/sl.po b/po/sl.po index 94ab47d..94ab47d 100644..100755 --- a/po/sl.po +++ b/po/sl.po diff --git a/po/sv.po b/po/sv.po index e4df3a1..e4df3a1 100644..100755 --- a/po/sv.po +++ b/po/sv.po diff --git a/po/sw.po b/po/sw.po index d797e12..d797e12 100644..100755 --- a/po/sw.po +++ b/po/sw.po diff --git a/po/te.po b/po/te.po index 58abd47..58abd47 100644..100755 --- a/po/te.po +++ b/po/te.po diff --git a/po/th.po b/po/th.po index 92e48fe..92e48fe 100644..100755 --- a/po/th.po +++ b/po/th.po diff --git a/po/tpi.po b/po/tpi.po index 840ef9f..840ef9f 100644..100755 --- a/po/tpi.po +++ b/po/tpi.po diff --git a/po/tr.po b/po/tr.po index d6e176a..d6e176a 100644..100755 --- a/po/tr.po +++ b/po/tr.po diff --git a/po/ug.po b/po/ug.po index d797e12..d797e12 100644..100755 --- a/po/ug.po +++ b/po/ug.po diff --git a/po/ur.po b/po/ur.po index e6b28d0..e6b28d0 100644..100755 --- a/po/ur.po +++ b/po/ur.po diff --git a/po/vi.po b/po/vi.po index 04d30df..04d30df 100644..100755 --- a/po/vi.po +++ b/po/vi.po diff --git a/po/wa.po b/po/wa.po index d797e12..d797e12 100644..100755 --- a/po/wa.po +++ b/po/wa.po diff --git a/po/yo.po b/po/yo.po index 328f81a..328f81a 100644..100755 --- a/po/yo.po +++ b/po/yo.po diff --git a/po/zh_CN.po b/po/zh_CN.po index 4d2e089..4d2e089 100644..100755 --- a/po/zh_CN.po +++ b/po/zh_CN.po diff --git a/po/zh_TW.po b/po/zh_TW.po index 57f064d..57f064d 100644..100755 --- a/po/zh_TW.po +++ b/po/zh_TW.po diff --git a/printactivity.py b/printactivity.py index d1211d3..0942200 100644..100755 --- a/printactivity.py +++ b/printactivity.py @@ -1,3 +1,4 @@ +# -*- coding: utf-8 -*- # Copyright (C) 2007, Red Hat, Inc. # Copyright (C) 2007 Collabora Ltd. # Copyright 2008 One Laptop Per Child @@ -128,7 +129,7 @@ class ReadActivity(activity.Activity): toolbox.add_toolbar(_('Print Setup'), self._print_setup_toolbar) self._print_setup_toolbar.show() - self._print_toolbar = PrintToolbar(self._view) + self._print_toolbar = PrintToolbar(self._view, self) self._print_toolbar._pdf.connect('clicked',self._save_pdf) self._print_toolbar._USB.props.sensitive = True toolbox.add_toolbar(_('Print'), self._print_toolbar) @@ -308,7 +309,7 @@ class ReadActivity(activity.Activity): os.remove(self._tempfile) os.link(self.pdf_file_path, self._tempfile) filepathr = 'file://' + self._tempfile - _logger.debug('PrintActivity._open_pdf: %s', filepathr) + _logger.debug('PrintActivity._open_pdf:returning path %s', filepathr) return filepathr def _delete_pdf(self, doit = True): @@ -461,11 +462,11 @@ class ReadActivity(activity.Activity): filepath -- string starting with file:// """ + self._title = self._jobject.metadata['title'] + try: - self._document = evince.factory_get_document(filepath) except GError: - self._title = self._jobject.metadata['title'] document = self._open_pdf(file_path, self._title) _logger.debug('the file path is: %s', document) self._document = evince.factory_get_document(document) @@ -474,9 +475,10 @@ class ReadActivity(activity.Activity): self._want_document = False self._view.set_document(self._document) self._read_toolbar.set_document(self._document) + self._print_setup_toolbar.set_document(self._document) - self._print_toolbar.setTitlePath(self._title,self._tempfile) - self._print_setup_toolbar.setTitlePath(self._title,self._tempfile) + self._print_toolbar.setTitlePath(self._title, self._tempfile) + self._print_setup_toolbar.setTitlePath(self._title, self._tempfile) if not self.metadata['title_set_by_user'] == '1': info = self._document.get_info() diff --git a/printer1.py b/printer1.py index a9e5b77..a9e5b77 100644..100755 --- a/printer1.py +++ b/printer1.py diff --git a/printerDeviceIcon.py b/printerDeviceIcon.py index c48a2cd..b8d3ce5 100644..100755 --- a/printerDeviceIcon.py +++ b/printerDeviceIcon.py @@ -82,14 +82,14 @@ class PrinterPalette(Palette): except TypeError: pass - def cancel(self,widget,key): + def cancel(self, widget, key): self._model.cancelAJob(key) self.menu.remove(self._hbars[key]) #self.connectEvents(self) del self._hbars[key] - def createHBars(self,status,title,jobid): + def createHBars(self, status, title, jobid): self._cancel = MenuItem('') self._icon = Icon(icon_size=gtk.ICON_SIZE_MENU) @@ -238,7 +238,7 @@ class PrinterManagerObserver(object): def deviceAdded(self, printerLoc): - self._PrinterObj = self._bus.get_object(_PRINTER_SERVICE,printerLoc) + self._PrinterObj = self._bus.get_object(_PRINTER_SERVICE,printerLoc) self._printeriface = dbus.Interface(self._PrinterObj, _PRINTER_IFACE) try: print self._printeriface.GetProperty('info.capabilities')[0] diff --git a/printscript.py b/printscript.py index eb7f064..3695b25 100644..100755 --- a/printscript.py +++ b/printscript.py @@ -1,4 +1,5 @@ #!/usr/bin/env python +# -*- coding: utf-8 -*- import gtk import gtkunixprint import logging @@ -38,31 +39,44 @@ class JustPrint: #self.printSettings. self.pgSetup = gtk.PageSetup() printerEnumerationObj = EnumeratePrinters() - self.printerObj = printerEnumerationObj.getPrinter()[1] + self.printerObj = printerEnumerationObj.getPrinters()[0] self._title = title self._filepath = filepath def printIt(self,): - cups = serverConnection() - cups._connect() - cups._print_Printer(self._filepath, self._title, self.printerObj) - #cups.close() - def setRange(self, textstring): - start, end = textstring.split('-',1) - self.printSettings.set_page_ranges([(int(start),int(end)),]) + printJob = PrintJob(self._title, self.printerObj, + self.printSettings, + self.pgSetup, self._filepath) + + def setRange(self, rangeList): + start = rangeList[0] + end = rangeList[1] + self.printSettings.set_page_ranges([(start-1,end-1,),]) + _logger.debug('the page ranges %s',self.printSettings.get_page_ranges()) + self.printSettings.set_print_pages(gtk.PRINT_PAGES_RANGES) def setPrinter(self, printer): self.printerObj = printer + + def getPrintSettings(self,): + return self.printSettings class EnumeratePrinters: def __init__(self,): - self.cups = serverConnection() - self.cups._connect() - self.printerList = self.cups._getPrintersList() - #self.cups.close() + self.printerList = [] + self.count = 0 + + loop = gtkunixprint.enumerate_printers(self.function,data=None, + wait=True) + + def function(self, printer, data=None): + #if printer.get_name() != _('Cups-PDF'): + _logger.debug(printer.get_name()) + self.printerList.append(printer) - def getPrinter(self,): + + def getPrinters(self,): return self.printerList class PrinterSetup(gtk.Dialog): @@ -205,7 +219,7 @@ class serverConnection: if self._location.find('${USER}') == -1: #Special Fedora case desktop = os.getenv("HOME")+'/.config/user-dirs.dirs' - #print desktop + #print "hello" try: f1 = open(desktop, 'r') except IOError: @@ -213,16 +227,17 @@ class serverConnection: _logger.debug("$DESKTOP isn't defined,\ so going to home directory") self._location = os.getenv("HOME") - f1.close() + _logger.debug('this is location 1 %s',self._location) else: self._location = os.getenv("HOME") for line in f1: - # print line[0:15] + #print line[0:15] if line[0:15] == 'XDG_'+folder+'_DIR': self._location = line[15:].rsplit('\n', 1)[0].strip('= "') self._location = self._location.replace('$HOME', os.getenv("HOME")) + _logger.debug('this is location2 %s',self._location) break @@ -233,10 +248,14 @@ class serverConnection: self._location = self._location.replace('${USER}', os.getenv("USER")) break #break to end 2nd for loop - - self._connection.printFile (_printer, _filename, _title, {}) - # break to end 1st for loop - return self._location+'/'+_title+'.pdf' + _logger.debug('this is location3 %s',self._location) + _title = _title.replace(")","_") + _title = _title.replace("(","_") + _title = _title.replace(" ","_") + self._connection.printFile (_printer, _filename, _title, {}) + + + return self._location + '/'+_title + '.pdf' def _print_Printer(self, filename, title, printer): diff --git a/printscriptCupsVersion.py b/printscriptCupsVersion.py new file mode 100755 index 0000000..750a85e --- /dev/null +++ b/printscriptCupsVersion.py @@ -0,0 +1,307 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +import gtk +import gtkunixprint +import logging +import threading +import cups +import sys +#import cupspk +from gettext import gettext as _ +import gobject +import gtk +import os +import tempfile +import time +import pygtk +_logger = logging.getLogger('print-activity:printscript') + + +class PageSetup(gtk.Dialog): + + def __init__(self, title=None,): + printDialog = gtkunixprint.PageSetupUnixDialog('Page Setup', + gtk.Window()) + printDialog.show_all() + printDialog.connect('response',self.processResponse) + + def processResponse(self, widget, settings): + _PAGE_SETUP = widget.get_page_setup() + widget.destroy() + return _PAGE_SETUP + + + +class JustPrint: + + def __init__(self, title, filepath): + self.printSettings = gtk.PrintSettings() + #self.printSettings. + self.pgSetup = gtk.PageSetup() + printerEnumerationObj = EnumeratePrinters() + self.printerObj = printerEnumerationObj.getPrinter()[1] + self._title = title + self._filepath = filepath + + def printIt(self,): + cups = serverConnection() + cups._connect() + cups._print_Printer(self._filepath, self._title, self.printerObj) + #cups.close() + def setRange(self, textstring): + start, end = textstring.split('-',1) + self.printSettings.set_page_ranges([(int(start),int(end)),]) + + def setPrinter(self, printer): + self.printerObj = printer + +class EnumeratePrinters: + + def __init__(self,): + self.cups = serverConnection() + self.cups._connect() + self.printerList = self.cups._getPrintersList() + #self.cups.close() + + def getPrinter(self,): + return self.printerList + +class PrinterSetup(gtk.Dialog): + + def __init__(self, title, filepath): + printDialog = gtkunixprint.PrintUnixDialog('Printer Settings', + gtk.Window()) + printDialog.show_all() + printDialog.connect('response',self.processResponse,title,filepath) + + def processResponse(self, widget, settings,title,filepath): + _PRINT_SETTINGS = widget.get_settings() + _PRINTER = widget.get_selected_printer() + #print _PRINTER.get_name() + widget.destroy() + pgSetup = self.getDefaultPageLayout() + + if settings == -5: + PrintJobObj = PrintJob(title, _PRINTER, + _PRINT_SETTINGS, + pgSetup, filepath) + + def getDefaultPageLayout(self,): + pgSetup = gtk.PageSetup() + return pgSetup + + + + +class PrintJob: + def __init__(self, title=None, + printer=None, + settings=None, + page_setup=None, + file_path=None): + + printJob = gtkunixprint.PrintJob(title,printer, + settings, page_setup) + printJob.set_source_file(file_path) + printJob.send(self.printDone) + + def printDone(self, arg1, arg2, arg3): + pass + +class serverConnection: + + def __init__ (self, host=None, port=None, encryption=None, lock=False): + + if host != None: + cups.setServer (host) + if port != None: + cups.setPort (port) + if encryption != None: + cups.setEncryption (encryption) + + + self._use_password = '' + self._use_user = cups.getUser () + self._server = cups.getServer () + self._port = cups.getPort() + self._encryption = cups.getEncryption () + if self._connect () == 1: + sys.exit() + self._prompt_allowed = True + self._operation_stack = [] + self._lock = lock + self._gui_event = threading.Event () + self.jobid = [] + #print self._server + + def _connect (self,): + cups.setUser (self._use_user) + create_object = cups.Connection + try: + self._connection = create_object (host=self._server, + port=self._port, + encryption=self._encryption) + except RuntimeError: + _logger.debug("check if cups server is functioning properly") + # print ('hey i messed up') + return 1 + + def _getTitle(self,_filepath): + title = os.path.split(_filepath)[1].rsplit('.',1)[0] + return title + + def _getPrintersList (self,): + self._dictPrinters = self._connection.getPrinters() + _thePrinters = self._dictPrinters.keys() + return _thePrinters + + def _getPrinterURI (self, name): + self._dictPrinters = self._connection.getPrinters () + _printerURI = self._dictPrinters[name]['device-uri'] + return _printerURI + + def _getDefaultPrinter (self,): + self._defaultPrinter = self._connection.getDefault () + return self._defaultPrinter + + def _setPrintDevice (self, device = None, uri = None ): + if device != None: + self._ourDevice = device + else: + self._ourDevice = _getDefaultPrinter () + + if uri != None: + self._ourURI = _getPrinterURI (self._ourDevice) + + setPrinterDevice (self, self._ourDevice, self._ourURI) + + + def _printPDF (self, _printer, _filename, _title = None): + + if _title == None: + _title = self._getTitle(_filename) + +# we require our script to not look up the editable names of the printing devices, +# but look up the unchangeable URI of the printer, so we do this: + + theprinters = self._getPrintersList() + self._location = '' + for printer in theprinters: + #print printer + if self._getPrinterURI(printer) == u'cups-pdf:/': + _printer = printer + +# Now we have the printer at hand +#lets open the config files and check the paths, and if user Directories are enabled +#Check for the paths, if a default $USER path exists, skip the condition and just use +#that if not go to user.dir, and also, that particular definition does not exist, use +#home dir, as it defaults to that + + # print _printer + f = open('/etc/cups/cups-pdf.conf', 'r') + for line in f: + if line[0:3] == 'Out': + folder = self._location = line[4:].rsplit('\n',1)[0] + folder = folder.strip(' $ { } ') + + if self._location.find('${USER}') == -1: #Special Fedora case + desktop = os.getenv("HOME")+'/.config/user-dirs.dirs' + #print "hello" + try: + f1 = open(desktop, 'r') + except IOError: + + _logger.debug("$DESKTOP isn't defined,\ + so going to home directory") + self._location = os.getenv("HOME") + _logger.debug('this is location 1 %s',self._location) + else: + self._location = os.getenv("HOME") + for line in f1: + #print line[0:15] + if line[0:15] == 'XDG_'+folder+'_DIR': + self._location = line[15:].rsplit('\n', + 1)[0].strip('= "') + self._location = self._location.replace('$HOME', + os.getenv("HOME")) + _logger.debug('this is location2 %s',self._location) + break + + + f1.close() + #print self._location + + else: + self._location = self._location.replace('${USER}', + os.getenv("USER")) + break #break to end 2nd for loop + _logger.debug('this is location3 %s',self._location) + _title = _title.replace(")","_") + _title = _title.replace("(","_") + _title = _title.replace(" ","_") + self._connection.printFile (_printer, _filename, _title, {}) + + + return self._location + '/'+_title + '.pdf' + + + def _print_Printer(self, filename, title, printer): + self._connection.printFile (printer, filename, title, {}) + + def _printtoPrinter (self,_filename, _title=None): + if _title == None: + _title = self._getTitle(_filename) + printer = self._getDefaultPrinter() + if self._getPrinterURI(printer) != u'cups-pdf:/': + self._connection.printFile (printer, _filename, _title, {}) + return True + return False + + def _selectDefaultPrinter (self,_printer): + self._connection.setDefault(_printer) + + def _getLiveJobQueue (self,noOfJobs=None): + if noOfJobs == None: + limit = -1 + else: + limit = noOfJobs + return self._connection.getJobs('not-completed', True, limit, -1) + + def _getCompletedJobQueue (self, noOfJobs = None): + if noOfJobs == None: + limit = -1 + else: + limit = noOfJobs + return self._connection.getJobs('completed', True, limit, -1) + + def _clearJobQueue (self,): + printers = self._getPrintersList() + for printer in printers: + printeruri = self._getPrinterURI(printer) + self._connection.cancelAllJobs(printeruri,False,True) + return True + + def _clearPrinterQueue(self,printer): + printeruri = self._getPrinterURI(printer) + self._connection.cancelAllJobs(printeruri,False,True) + + def _cancelAJob(self,jobid): + self._connection.cancelJob(jobid) + return True + + + + + + + + + + + + +#printer = JustPrint('lolmax','/home/iwikiwi/lolmax.odt') + +#hello = serverConnection() +#lol = hello._printPDF('Cups-PDF','/home/iwikiwi/lolmax.odt','lolmax') +#print '\''+ lol + '\'' diff --git a/printtoolbar.py b/printtoolbar.py index 386042b..53a6394 100644..100755 --- a/printtoolbar.py +++ b/printtoolbar.py @@ -1,4 +1,4 @@ -# Copyright (C) 2006, Red Hat, Inc. +# -*- coding: utf-8 -*- # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -14,7 +14,6 @@ # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -import logging from gettext import gettext as _ import re @@ -22,7 +21,11 @@ import pango import gobject import gtk import evince +import xmlrpclib +from cookiemagic import XSCookieTransport +from sugar.graphics.alert import Alert +from sugar.graphics.icon import Icon from sugar.graphics.toolbutton import ToolButton from sugar.graphics.menuitem import MenuItem from sugar.graphics import iconentry @@ -36,13 +39,15 @@ class PrintToolbar(gtk.Toolbar): __gtype_name__= 'PrintToolbar' - def __init__(self, evince_view, title=None, tempfile=None): + def __init__(self, evince_view, activity, title=None, tempfile=None): gtk.Toolbar.__init__(self) self._evince_view = evince_view + self._activity = activity self._document = None self._title = title self._path = tempfile + self._username = '' self._pdf = ToolButton('document-save') self._pdf.set_tooltip(_('save-PDF')) @@ -52,9 +57,18 @@ class PrintToolbar(gtk.Toolbar): self._moodle = ToolButton() self._moodle.set_tooltip(_('Send-Moodle')) - self._moodle.props.sensitive = False + self._moodle.props.sensitive = True self.insert(self._moodle, -1) self._moodle.show() + self._moodle.connect('clicked', self.xmlrpc,) + + palette = self._moodle.get_palette() + menu_item = MenuItem(_('Moodle Username')) + menu_item.connect('activate', self.username_textbox) + palette.menu.append(menu_item) + menu_item.show() + + self._USB = ToolButton('printer') self._USB.set_tooltip(_('printer')) @@ -64,9 +78,57 @@ class PrintToolbar(gtk.Toolbar): self._USB.connect('clicked', self.printing) + def username_textbox(self, widget): + widget = gtk.Window('Username') + + + + + def xmlrpc(self, widget): + + + ''' window = gtk.Window(gtk.WINDOW_TOPLEVEL) + window.set_size_request(200, 100) + window.set_title("Send to Moodle") + window.connect("delete_event", lambda w,e: gtk.main_quit()) + menu = gtk.Menu() + + if username == '': + self._stop_alert = Alert() + self._stop_alert.props.title = _('Moodle Username not entered') + self._stop_alert.props.msg = _('Please Enter your username') + ok_icon = Icon(icon_name='dialog-ok') + self._stop_alert.add_button(gtk.RESPONSE_OK, _('Ok'), ok_icon) + ok_icon.show() + self._activity.add_alert(self._stop_alert) + self._stop_alert.connect('response', self.__stop_response_cb) + self._stop_alert.show() + return + + # This is how you get the url to the school server. + client = gconf.client_get_default() + backup_url = client.get_string('/desktop/sugar/backup_url') + if not backup_url: + _logger.debug('seed_xs_cookie: Not registered with Schoolserver') + return + + jabber_server = client.get_string( + '/desktop/sugar/collaboration/jabber_server') + ''' + + server = xmlrpclib.ServerProxy("http://localhost/~iwikiwi/moodle1/web/mod/print/print_xmlrpc.php", transport=XSCookieTransport()) + filein = open(self._path, 'rb') + contents = filein.read() + filein.close() + bits = xmlrpclib.Binary(contents) + server.send_func(bits,'lol',) + + def __stop_response_cb(self, alert, response_id): + self._activity.remove_alert(alert) + def printing(self, widget): justPrint = JustPrint(self._title, self._path) - justPrint.Printit() + justPrint.PrintIt() def setTitlePath(self, title, path): self._title = title @@ -91,26 +153,37 @@ class PrintSetupToolbar(gtk.Toolbar): total_page_item.add(self._noOfPagesL) total_page_item.show() self.insert(total_page_item, -1) - self._noOfPagesTB = gtk.Entry() - self._noOfPagesTB.connect("activate", self.TBfunction, - gtk.RESPONSE_OK) - self._noOfPagesTB.set_editable(True) - self._noOfPagesTB.show() + self._noOfPages1 = gtk.SpinButton() + self._noOfPages1.set_numeric(True) + self._noOfPages2 = gtk.SpinButton() + self._noOfPages2.set_numeric(True) + #self._noOfPages1.connect("value-changed", self.SetPage, + # gtk.RESPONSE_OK) + #self._noOfPages2.connect("value-changed", self.SetPage, + # gtk.RESPONSE_OK) + + #self._noOfPagesTB.set_editable(True) + self._noOfPages1.show() + self._noOfPages2.show() total_page_item1 = gtk.ToolItem() - - total_page_item1.add(self._noOfPagesTB) + total_page_item2 = gtk.ToolItem() + total_page_item1.add(self._noOfPages1) + total_page_item2.add(self._noOfPages2) total_page_item1.show() + total_page_item2.show() self.insert(total_page_item1, -1) + self.insert(total_page_item2, -1) + printerEnumerationObj = EnumeratePrinters() - printerObjList = printerEnumerationObj.getPrinter() + self.printerObjList = printerEnumerationObj.getPrinters() self._printerComboBox = gtk.combo_box_new_text() self._printerComboBox.append_text('Printer:') - for printer in printerObjList: - - self._printerComboBox.append_text(printer) + for printer in self.printerObjList: + self._printerComboBox.append_text(printer.get_name()) self._printerComboBox.connect('changed', self.changed_cb) + self._printerComboBox.set_active(0) self._printerComboBox.show() total_page_item2 = gtk.ToolItem() @@ -125,25 +198,40 @@ class PrintSetupToolbar(gtk.Toolbar): self._USB.show() self._USB.connect('clicked', self.printing) + + #def SetPage(self,widget): + # pass + + def set_document(self, document): + self._document = document + noOfPages = self._document.get_n_pages() + self._noOfPages1.set_range(0, noOfPages) + self._noOfPages2.set_range(0, noOfPages) + self._noOfPages2.set_value(noOfPages) + self.adj1 = gtk.Adjustment(1.0, 1.0, noOfPages, 1.0, 5.0, 0.0) + self.adj2 = gtk.Adjustment(1.0, 1.0, noOfPages, 1.0, 5.0, 0.0) + + self._noOfPages1.configure(self.adj1, 0, 0) + self._noOfPages2.configure(self.adj2, 0, 0) - def TBfunction(self, widget, entry): - - entry_text = widget.get_text() - self.justPrint = JustPrint(self._title, self._path) - self.justPrint.setRange(entry_text) + def changed_cb(self, combobox): model = combobox.get_model() index = combobox.get_active() if index: - self._printerToSet = model[index][0] - self.justPrint.setPrinter(self._printerToSet) + self._printerToSet = self.printerObjList[index-1] return def printing(self, widget): - + + range_params = [self._noOfPages1.get_value_as_int(), + self._noOfPages2.get_value_as_int(),] + self.justPrint = JustPrint(self._title, self._path) + self.justPrint.setRange(range_params) + self.justPrint.setPrinter(self._printerToSet) self.justPrint.printIt() def setTitlePath(self, title, path): @@ -225,8 +313,7 @@ class ReadToolbar(gtk.Toolbar): self.insert(navitem, -1) navitem.show_all() - - + def set_document(self, document): self._document = document page_cache = self._document.get_page_cache() diff --git a/test.pcap b/test.pcap index 809ca89..809ca89 100644..100755 --- a/test.pcap +++ b/test.pcap Binary files differ diff --git a/xmlrpc.txt b/xmlrpc.txt index 7a68751..7a68751 100644..100755 --- a/xmlrpc.txt +++ b/xmlrpc.txt -- cgit v0.9.1