#!/usr/bin/env python

# Adapted from the Quickprint IPP server code (http://quikprint.mit.edu)
# Modifications and additions written by Jessica Hamrick (jhamrick@mit.edu)

# Notes and Todo:
#   - make sure package creates gutenbach folder in /var/log

import os, sys
import cgi, cgitb
import logging
import MySQLdb
import ipplib

from ipprequest import IPPRequest
from tempfile import mkstemp
from shutil import move
from logging import debug, info, warning, error, critical

# set up logging
LOGFILE = "/var/log/gutenbach/ipp.log"
logging.basicConfig(filename=LOGFILE, level=logging.DEBUG)
cgitb.enable(logdir='/var/log/gutenbach/cgi.log')

# make sure a temporary folder exists
TEMPDIR = '/tmp/gutenbach/ipp'
try:
    if not os.path.exists(TEMPDIR):
        info("Creating temporay directory '%s'" % TEMPDIR)
        os.makedirs(TEMPDIR)
except e, Exception:
    error("Could not create temporary directory '%s'" % TEMPDIR)

# print the content type for our request
print "Content-type: application/ipp\n"

class IPPServer(object):
    
    # nothing to do in the init
    def __init__(self):
        """
        This function doesn't actually do anything.
        """
        pass

    # this function processes an IPP request and sends a response
    def process(self, request_in, response_out):
        """
        Processes an IPP request and sends a response.

        Arguments:

            request_in -- a file handle to read in the request

            request_out -- a file handle to print the response
        """
        
        # parse the request from request_in
        request = IPPRequest(request=request_in)

        # create the response, copying the version, operation-id, and
        # request-id from the request
        response = IPPRequest(version=request.version,
                              operation_id=request.operation_id,
                              request_id=request.request_id)
        
        handler = getattr(self, "_operation_%d" % request.operation_id, None)

        response._operation_attributes = [[]]
        response._operation_attributes[0] = filter( \
            lambda x: x[0] in ('attributes-charset', 'attributes-natural-language', 'printer-uri'),
            request._operation_attributes[0])

        # f = file('/tmp/gutenbach/ipp/printer2.log','a')
        # f.write("\n" + "*"*80 + "\n")
        # f.write(str(request))
        if handler is not None:
            response.setOperationId(handler(request, response))
            data_out = response.dump()
            response_out.write(data_out)
            response_test = IPPRequest(data=data_out)
            response_test.parse()
        #     f.write("\n" + "-"*80 + "\n")
        #     f.write(str(response_test))
        # f.write("\n" + "*"*80 + "\n")
        # f.close()

    def _operation_2(self, request, response):
        """print-job response"""
        (fno, fname) = mkstemp(dir='/tmp/gutenbach/ipp')
        os.write(fno, request.data)
        os.close(fno)
        opattr = filter(lambda x: x[0] in ('job-name'),
            request._operation_attributes[0])
        jname = 'unknown'
        if len(opattr) and opattr[0][0] == 'job-name':
            jname = opattr[0][1][0][1]
        jstat = os.stat(fname)
        jsize = jstat.st_size
        c = db.cursor()
        c.execute("INSERT INTO job (juser, jname, jfile, jsize, jtype) VALUES (%s, %s, %s, %s, %s)", \
                (AUTH, jname, fname, jsize, 'PostScript',))
        jid = db.insert_id()
        jfile = '/mit/gutenbach/jobs/' + AUTH + '_' + str(jid)
        move(fname, jfile)
        c.execute("UPDATE job SET jfile=%s, dupdated=NOW() WHERE jid=%s", \
                (jfile, str(jid),))
        response._job_attributes = [[ \
            ('job-id', [('integer', jid)]), \
            ('printer-uri', [('uri', printer_uri)]), \
            ('job-state', [('enum', ipplib.IPP_JOB_HELD)])]]
        return ipplib.IPP_OK

    def _operation_8(self, request, response):
        """delete-job response"""
        opattr = filter(lambda x: x[0] in ('job-id'),
            request._operation_attributes[0])
        if len(opattr) and opattr[0][0] == 'job-id':
            jid = opattr[0][1][0][1]
            c = db.cursor()
            c.execute("UPDATE job SET jstate = 'DEL' WHERE juser = %s AND jid = %s", \
                (AUTH, int(jid)))
        return ipplib.IPP_OK

    def _operation_9(self, request, response):
        """get-job-properties response"""
        opattr = filter(lambda x: x[0] in ('job-id'),
            request._operation_attributes[0])
        if len(opattr) and opattr[0][0] == 'job-id':
            jid = opattr[0][1][0][1]
        response._job_attributes.append([ \
            ('job-id', [('integer', jid)]), \
        #    ('job-name', [('nameWithoutLanguage', x[1])]), \
            ('job-originating-user-name', [('nameWithoutLanguage', AUTH)]), \
        #    ('job-k-octets', [('integer', x[2]/1024)]), \
            ('job-state', [('enum', ipplib.IPP_JOB_COMPLETE)])
        ])
        return ipplib.IPP_OK

    def _operation_10(self, request, response):
        """get-jobs response"""
        c = db.cursor()
        c.execute("SELECT jid, jname, jsize, jstate FROM job WHERE juser = %s AND jstate != %s ORDER BY dadded", \
            (AUTH, 'DEL',))
        response._job_attributes = []
        for x in c.fetchall():
            if x[3] == 'NEW':
                state = ipplib.IPP_JOB_HELD
            elif x[3] == 'DONE':
                state = ipplib.IPP_JOB_COMPLETE
            else:
                state = 0
            response._job_attributes.append([ \
                ('job-id', [('integer', x[0])]), \
                ('job-name', [('nameWithoutLanguage', x[1])]), \
                ('job-originating-user-name', [('nameWithoutLanguage', AUTH)]), \
                ('job-k-octets', [('integer', x[2]/1024)]), \
                ('job-state', [('enum', state)])
            ])
        return ipplib.IPP_OK

    def _operation_11(self, request, response):
        """get-printer-attributes response"""
        response._printer_attributes = \
            [[('printer-name', [('nameWithoutLanguage', 'Gutenbach')])]]
        return ipplib.IPP_OK

IPPServer().process(sys.stdin,sys.stdout)
