作者:JohnO
项目:cups-connecto
// connect calls C.httpConnect2 to create a new, open connection to
// the CUPS server specified by environment variables, client.conf, etc.
//
// connect also acquires the connection semaphore and locks the OS
// thread to allow the CUPS API to use thread-local storage cleanly.
//
// The caller is responsible to close the connection when finished
// using cupsCore.disconnect.
func (cc *cupsCore) connect() (*C.http_t, error) {
cc.connectionSemaphore.Acquire()
// Lock the OS thread so that thread-local storage is available to
// cupsLastError() and cupsLastErrorString().
runtime.LockOSThread()
var http *C.http_t
select {
case h := <-cc.connectionPool:
// Reuse another connection.
http = h
default:
// No connection available for reuse; create a new one.
http = C.httpConnect2(cc.host, cc.port, nil, C.AF_UNSPEC, cc.encryption, 1, cc.connectTimeout, nil)
if http == nil {
defer cc.disconnect(http)
return nil, fmt.Errorf("Failed to connect to CUPS server %s:%d because %d %s",
C.GoString(cc.host), int(cc.port), int(C.cupsLastError()), C.GoString(C.cupsLastErrorString()))
}
}
return http, nil
}
作者:JohnO
项目:cups-connecto
// getPPD gets the filename of the PPD for a printer by calling
// C.cupsGetPPD3. If the PPD hasn't changed since the time indicated
// by modtime, then the returned filename is a nil pointer.
//
// Note that modtime is a pointer whose value is changed by this
// function.
//
// The caller is responsible to C.free the returned *C.char filename
// if the returned filename is not nil.
func (cc *cupsCore) getPPD(printername *C.char, modtime *C.time_t) (*C.char, error) {
bufsize := C.size_t(filePathMaxLength)
buffer := (*C.char)(C.malloc(bufsize))
if buffer == nil {
return nil, errors.New("Failed to malloc; out of memory?")
}
C.memset(unsafe.Pointer(buffer), 0, bufsize)
var http *C.http_t
if !cc.hostIsLocal {
// Don't need a connection or corresponding semaphore if the PPD
// is on the local filesystem.
// Still need OS thread lock; see else.
var err error
http, err = cc.connect()
if err != nil {
return nil, err
}
defer cc.disconnect(http)
} else {
// Lock the OS thread so that thread-local storage is available to
// cupsLastError() and cupsLastErrorString().
runtime.LockOSThread()
defer runtime.UnlockOSThread()
}
httpStatus := C.cupsGetPPD3(http, printername, modtime, buffer, bufsize)
switch httpStatus {
case C.HTTP_STATUS_NOT_MODIFIED:
// Cache hit.
if len(C.GoString(buffer)) > 0 {
os.Remove(C.GoString(buffer))
}
C.free(unsafe.Pointer(buffer))
return nil, nil
case C.HTTP_STATUS_OK:
// Cache miss.
return buffer, nil
default:
if len(C.GoString(buffer)) > 0 {
os.Remove(C.GoString(buffer))
}
C.free(unsafe.Pointer(buffer))
cupsLastError := C.cupsLastError()
if cupsLastError != C.IPP_STATUS_OK {
return nil, fmt.Errorf("Failed to call cupsGetPPD3(): %d %s",
int(cupsLastError), C.GoString(C.cupsLastErrorString()))
}
return nil, fmt.Errorf("Failed to call cupsGetPPD3(); HTTP status: %d", int(httpStatus))
}
}
作者:JohnO
项目:cups-connecto
// printFile prints by calling C.cupsPrintFile2().
// Returns the CUPS job ID, which is 0 (and meaningless) when err
// is not nil.
func (cc *cupsCore) printFile(user, printername, filename, title *C.char, numOptions C.int, options *C.cups_option_t) (C.int, error) {
http, err := cc.connect()
if err != nil {
return 0, err
}
defer cc.disconnect(http)
C.cupsSetUser(user)
jobID := C.cupsPrintFile2(http, printername, filename, title, numOptions, options)
if jobID == 0 {
return 0, fmt.Errorf("Failed to call cupsPrintFile2() for file %s: %d %s",
C.GoString(filename), int(C.cupsLastError()), C.GoString(C.cupsLastErrorString()))
}
return jobID, nil
}
作者:rufil7
项目:cups-connecto
// CreateTempFile calls cupsTempFd() to create a new file that (1) lives in a
// "temporary" location (like /tmp) and (2) is readable by CUPS. The caller
// is responsible for deleting the file.
func CreateTempFile() (*os.File, error) {
length := C.size_t(filePathMaxLength)
filename := (*C.char)(C.malloc(length))
if filename == nil {
return nil, errors.New("Failed to malloc(); out of memory?")
}
defer C.free(unsafe.Pointer(filename))
createTempFileLock.Lock()
defer createTempFileLock.Unlock()
runtime.LockOSThread()
defer runtime.UnlockOSThread()
fd := C.cupsTempFd(filename, C.int(length))
if fd == C.int(-1) {
err := fmt.Errorf("Failed to call cupsTempFd(): %d %s",
int(C.cupsLastError()), C.GoString(C.cupsLastErrorString()))
return nil, err
}
return os.NewFile(uintptr(fd), C.GoString(filename)), nil
}
作者:JohnO
项目:cups-connecto
// doRequest calls cupsDoRequest().
func (cc *cupsCore) doRequest(request *C.ipp_t, acceptableStatusCodes []C.ipp_status_t) (*C.ipp_t, error) {
http, err := cc.connect()
if err != nil {
return nil, err
}
defer cc.disconnect(http)
if C.ippValidateAttributes(request) != 1 {
return nil, fmt.Errorf("Bad IPP request: %s", C.GoString(C.cupsLastErrorString()))
}
response := C.cupsDoRequest(http, request, C.POST_RESOURCE)
if response == nil {
return nil, fmt.Errorf("cupsDoRequest failed: %d %s", int(C.cupsLastError()), C.GoString(C.cupsLastErrorString()))
}
statusCode := C.getIPPRequestStatusCode(response)
for _, sc := range acceptableStatusCodes {
if statusCode == sc {
return response, nil
}
}
return nil, fmt.Errorf("IPP status code %d", int(statusCode))
}