/* Copyright 1998 Acorn Computers Ltd * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* * C.Printers -- Does printing-related things * * 16-12-94 INH Original * */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include "kernel.h" #include "swis.h" #include "stdtypes.h" #include "printers.h" #include "smb.h" #include "omni.h" struct pjob_info /* Print job info */ { int tag; #define PJOB_VALID_TAG 0x57202116 int status; /* Only valid if tag is PJOB_VALID_TAG */ #define PJOB_OPEN 0 #define PJOB_CLOSED 1 #define PJOB_ABORTED 2 char SMBletter; /* letter representing printer connection */ int SMBhandle; /* handle to which to print */ int serialno; /* Serial number of job */ int bytecount; /* Number of bytes sent */ }; #define PJOB_BLOCK_SIZE 20 struct pjob_block /* A bunch of print jobs */ { struct pjob_block *next; struct pjob_info jobs[PJOB_BLOCK_SIZE]; }; /* Globals --------------------------------------- */ static struct pjob_block *JobBlockList; static int JobSerialNo; /* Serial number of last job created */ /* CheckDisconnect ------------------------------- */ static void CheckDisconnect ( char drvletter ) { int i; struct pjob_block *pPB; /* Look for any job using this connection */ for ( pPB = JobBlockList; pPB != NULL; pPB = pPB->next ) { for ( i=0; i < PJOB_BLOCK_SIZE; i++ ) { if ( pPB->jobs[i].tag == PJOB_VALID_TAG && pPB->jobs[i].SMBletter == drvletter ) return; } } /* No one using it - we can disconnect */ debug0("Server disconnect\n"); SMB_DeleteShare(drvletter); } /* ---------------------- */ static struct pjob_info *AllocPJob ( void ) { int i; struct pjob_block *pPB; /* Look for free slot in existing chunks */ for ( pPB = JobBlockList; pPB != NULL; pPB = pPB->next ) { for ( i=0; i < PJOB_BLOCK_SIZE; i++ ) if ( pPB->jobs[i].tag != PJOB_VALID_TAG ) return &(pPB->jobs[i]); } /* If none suitable, alloc new block */ pPB = (struct pjob_block *)malloc ( sizeof(struct pjob_block) ); if ( pPB == NULL ) return NULL; /* Malloc failure */ /* Set all slots free */ for ( i=0; i < PJOB_BLOCK_SIZE; i++ ) pPB->jobs[i].tag = 0; /* Add block to list */ pPB->next = JobBlockList; JobBlockList = pPB; return &(pPB->jobs[0]); } /* Prn_CreateJob() ------------------------------------- */ err_t Prn_CreateJob ( char *servname, char *prnname, char *userid, char *passwd, int *jobid_out ) { char namebuf[16]; err_t res; char drvletter; int handle; struct pjob_info * pPJ; debug2("Create job srv=%s prn=%s ", servname, prnname ); debug2("usr=%s passwd=%s\n", userid==NULL ? "<NULL>":userid, passwd==NULL ? "<NULL>":passwd ); /* Try to alloc job handle */ *jobid_out = 0; pPJ = AllocPJob (); if ( pPJ == NULL ) return ENOHANDLES; /* Try to connect to server - most likely we will already be connected, in which case don't worry */ res = SMB_CreateShare ( SHR_PRINTER, CREATE_NORMAL, servname, prnname, userid, passwd, &drvletter ); if ( res != OK ) return res; Omni_AddInfo ( OAI_PRINTER, servname, prnname ); sprintf ( namebuf, "%05d", ++JobSerialNo ); /* Open printer spool file */ res = SMB_OpenPrinter ( drvletter, namebuf, &handle ); if ( res != OK ) { debug1("Printer open failed, code %d", res ); /* Disconnect only if no-one else is using this connection */ CheckDisconnect(drvletter); return res; } /* So far so good: */ pPJ->SMBhandle = handle; pPJ->SMBletter = drvletter; pPJ->status = PJOB_OPEN; pPJ->serialno = JobSerialNo; pPJ->bytecount = 0; pPJ->tag = PJOB_VALID_TAG; *jobid_out = (int) pPJ; debug1( "Created job %d\n", (int) pPJ ); return OK; } /* ---------------------------- */ err_t Prn_WriteData ( int jobid, char *data, int datalen ) { err_t res; struct pjob_info *pPJ; debug2( "Write job %d, %d chars\n", jobid, datalen ); pPJ = (struct pjob_info *)jobid; if ( pPJ == NULL || pPJ->tag != PJOB_VALID_TAG || pPJ->status != PJOB_OPEN ) return EBADPARAM; res = SMB_WritePrinter ( pPJ->SMBhandle, (BYTE *)data, datalen ); if ( res != OK ) return res; pPJ->bytecount += datalen; return OK; } /* ---------------------------- */ err_t Prn_CloseJob ( int jobid, bool abort ) { err_t res; struct pjob_info *pPJ; debug1( "Close job %d\n", jobid ); pPJ = (struct pjob_info *)jobid; if ( pPJ == NULL || pPJ->tag != PJOB_VALID_TAG || pPJ->status != PJOB_OPEN ) return EBADPARAM; res = SMB_ClosePrinter ( pPJ->SMBhandle ); if ( res != OK ) { debug1("Close prn failed, code %d", res); return res; } if ( abort ) pPJ->status = PJOB_ABORTED; /* Ignore really!! */ else pPJ->status = PJOB_CLOSED; return OK; } /* ---------------------------- */ err_t Prn_GetJobStatus ( int jobid, struct JobStatus *pJS ) { struct pjob_info *pPJ; debug1( "Get job status %d\n", jobid ); pPJ = (struct pjob_info *)jobid; if ( pPJ == NULL || pPJ->tag != PJOB_VALID_TAG ) return EBADPARAM; switch ( pPJ->status ) { case PJOB_OPEN: pJS->lclstatus = (pPJ->bytecount > 0) ? 5 : 3; break; case PJOB_CLOSED: pJS->lclstatus = 7; /* 'Transfer complete' status */ break; case PJOB_ABORTED: pJS->lclstatus = 11; /* 'Terminal error' */ break; default: pJS->lclstatus = 0; /* No info available */ } pJS->lclcount = pPJ->bytecount; pJS->lclerror = 0; pJS->rmtstatus = 0; /* No info available */ pJS->rmtcount = 0; pJS->rmterror = 0; return OK; } /* ---------------------------- */ err_t Prn_ClearJob ( int jobid ) { struct pjob_info *pPJ; debug1( "Kill job %d\n", jobid ); if ( jobid == 0 ) /* Clear all inactive jobs */ { int i; struct pjob_block *pPB; for ( pPB = JobBlockList; pPB != NULL; pPB = pPB->next ) { /* Check for inactive jobs */ for ( i=0; i<PJOB_BLOCK_SIZE; i++ ) if ( pPB->jobs[i].tag == PJOB_VALID_TAG && pPB->jobs[i].status != PJOB_OPEN ) { Prn_ClearJob( (int) &(pPB->jobs[i]) ); } } return OK; } /* Clear specific job */ pPJ = (struct pjob_info *)jobid; if ( pPJ->tag != PJOB_VALID_TAG ) return EBADPARAM; if ( pPJ->status == PJOB_OPEN ) Prn_CloseJob ( jobid, false ); /* See if we should disconnect server */ pPJ->tag = 0; CheckDisconnect ( pPJ->SMBletter ); return OK; } /* --------------------- */ bool Prn_Init (void) { JobBlockList = NULL; JobSerialNo = 0; return true; } /* --------------------- */ void Prn_Shutdown (void) { int i; struct pjob_block *pPB, *pPB_next; /* We assume SMB_Shutdown will kill of all connections */ for ( pPB = JobBlockList; pPB != NULL; pPB = pPB_next ) { /* Invalidate all pjob_id's */ for ( i=0; i<PJOB_BLOCK_SIZE; i++ ) pPB->jobs[i].tag = 0; pPB_next = pPB->next; free ( pPB ); } }