/*++ Copyright (c) 1995 Microsoft Corporation Module Name: psndsdb.c Abstract: Read the Print Configuration Attributes $Log: N:\NT\PRIVATE\NW4\NWSCRIPT\VCS\PS40DB.C $ * * Rev 1.4 10 Apr 1996 14:23:28 terryt * Hotfix for 21181hq * * Rev 1.4 12 Mar 1996 19:55:22 terryt * Relative NDS names and merge * * Rev 1.3 04 Jan 1996 18:57:36 terryt * Bug fixes reported by MS * * Rev 1.2 22 Dec 1995 14:26:22 terryt * Add Microsoft headers * * Rev 1.1 20 Nov 1995 15:09:46 terryt * Context and capture changes * * Rev 1.0 15 Nov 1995 18:07:52 terryt * Initial revision. --*/ #include "common.h" extern DWORD SwapLong(DWORD number); extern char *TYPED_USER_NAME; unsigned int PS40GetJobName( unsigned int NDSCaptureFlag, unsigned short SearchFlag, unsigned char *pOwner, unsigned char *pJobName, PPS_JOB_RECORD pJobRecord, unsigned char GetDefault ); #include #define NWPS_JOB_NAME_SIZE 32 /* 31 bytes and a '\0' */ #define NWPS_FORM_NAME_SIZE 12 /* 12 bytes and a '\0' */ #define NWPS_BANNER_NAME_SIZE 12 /* 12 bytes and a '\0' */ #define NWPS_BANNER_FILE_SIZE 12 /* 12 bytes and a '\0' */ #define NWPS_DEVI_NAME_SIZE 32 /* 32 bytes and a '\0' */ #define NWPS_MODE_NAME_SIZE 32 /* 32 bytes and a '\0' */ #define NWPS_BIND_NAME_SIZE 48 #define NWPS_MAX_NAME_SIZE 514 /* // NWPS_Job_Old_Db_Hdr is the first record in the 4.0 PrnConDB database. // It contains the following information about the database: // The version number, // the number of NWPS_Job_Rec records in PrnConDB, // the name of the default print job configuration and // the name of the job record owner. */ typedef struct { char text[ 76 ]; /* Printcon database. Version 4.0 */ char DefaultJobName[ 32 ]; /* Name of default Job */ char Owner[ 256 ]; /* owner of the job record */ WORD NumberOfRecords; /* # of NWPS_Job_Rec's in PrnConDB */ WORD NumberOfBlocks; /* # of 50-(NWPS_Job_Name_Rec) blocks */ BYTE MajorVersion; /* 4 */ BYTE MinorVersion; /* 0 */ } PRINTCON_40_HEADER; #define PRINTCON_40_HEADER_SIZE sizeof(PRINTCON_40_HEADER) /* // NWPS_Job_41_Db_Hdr is the first record in the 4.1 PrnConDB database. // It contains the following information about the database: // The version number, // the number of NWPS_Job_Rec records in PrnConDB, // the name of the default print job configuration and // the name of the job record owner IN UNICODE. */ typedef struct { char text[ 76 ]; /* Printcon database. Version 4.1 */ char DefaultJobName[ 32 ]; /* Name of default Job */ char unused[ 256 ]; /* no longer used. */ WORD NumberOfRecords; /* # of NWPS_Job_Rec's in PrnConDB */ WORD NumberOfBlocks; /* # of 50-(NWPS_Job_Name_Rec) blocks */ BYTE MajorVersion; /* 4 */ BYTE MinorVersion; /* 1 unicode defaultPJOwner etc. */ WORD Owner[ 256 ]; /* owner of the default job record */ } PRINTCON_41_HEADER; #define PRINTCON_41_HEADER_SIZE sizeof(PRINTCON_41_HEADER) /* // NWPS_Job_Name_Rec is the type of record found in the // second section of the PrnConDB database. Each one of // these records contains the name of each NWPS_Job_Rec // and a pointer to their location in the third section of // the database. There is space set aside in this second // section for fifty NWPS_Job_Name_Rec records; if this // limit is exceeded then another fifty-record block following // the first one is allocated after the third section of the // database is moved down to make room for the expansion. */ typedef struct { char JobName[ NWPS_JOB_NAME_SIZE ]; /* 1 - 31 chars long + 0 */ long JobRecordOffset; /* Offset of the record // (from the beginning // of the 3rd section for 4.0 // databases and from the start // of the file for pre-4.0) */ } JOB_NAME_AREA; #define JOB_NAME_AREA_SIZE sizeof(JOB_NAME_AREA) typedef struct { union { struct { DWORD DataType : 1; /* 0=Byte stream 1 = Text */ DWORD FormFeed : 1; /* 0 = FF; 1 = suppress FF */ DWORD NotifyWhenDone : 1; /* 0 = no, 1 = yes */ DWORD BannerFlag : 1; /* 0 = no, 1 = yes */ DWORD AutoEndCap : 1; /* 0 = no, 1 = yes */ DWORD TimeOutFlag: 1; /* 0 = no, 1 = yes */ DWORD SystemType : 3; /* 0 = bindery 1 = NDS */ DWORD Destination: 3; /* 0 = queue 1 = printer */ DWORD unknown : 20; }; DWORD PrintJobFlags; }; WORD NumberOfCopies; /* 1 - 65,000 */ WORD TimeoutCount; /* 1 - 1,000 */ BYTE TabSize; /* 1 - 18 */ BYTE LocalPrinter; /* 0=Lpt1, 1=Lpt2, 2=Lpt3 etc. */ char FormName[ NWPS_FORM_NAME_SIZE + 2 ]; /* 1-12 chars */ char Name[ NWPS_BANNER_NAME_SIZE + 2 ]; /* 1-12 chars */ char BannerName[ NWPS_BANNER_FILE_SIZE + 2 ]; /* 1-12 chars */ char Device[ NWPS_DEVI_NAME_SIZE + 2 ]; /* 1-32 chars */ char Mode[ NWPS_MODE_NAME_SIZE + 2 ]; /* 1-32 chars */ union { struct { /* pad structures on even boundries */ char Server[ NWPS_BIND_NAME_SIZE + 2 ]; /* 2-48 chars */ char QueueName[ NWPS_BIND_NAME_SIZE + 2 ]; /* 1-48 chars */ char PrintServer[ NWPS_BIND_NAME_SIZE + 2 ]; /* 1-48 chars */ } NonDS; char DSObjectName[ NWPS_MAX_NAME_SIZE ]; } u; BYTE reserved[390]; /* Adds up to 1024 total (was 1026) */ } JOB_RECORD_AREA; #define JOB_RECORD_AREA_SIZE sizeof(JOB_RECORD_AREA) #include /*++ ******************************************************************* PS40JobGetDefault Routine Description: Get the default print job configuration from 40. Arguments: NDSCaptureFlag SearchFlag = pOwner = pJobName = A pointer to return the default job configuration name. pJobRecord = A pointer to return the default job configuration. Return Value: SUCCESSFUL 0x0000 PS_ERR_BAD_VERSION 0x7770 PS_ERR_GETTING_DEFAULT 0x7773 PS_ERR_OPENING_DB 0x7774 PS_ERR_READING_DB 0x7775 PS_ERR_READING_RECORD 0x7776 PS_ERR_INTERNAL_ERROR 0x7779 PS_ERR_NO_DEFAULT_SPECIFIED 0x777B INVALID_CONNECTION 0x8801 ******************************************************************* --*/ unsigned int PS40JobGetDefault( unsigned int NDSCaptureFlag, unsigned short SearchFlag, unsigned char *pOwner, unsigned char *pJobName, PPS_JOB_RECORD pJobRecord ) { return PS40GetJobName( NDSCaptureFlag, SearchFlag, pOwner, pJobName, pJobRecord, TRUE); } /*++ ******************************************************************* PS40JobRead Routine Description: Get the print job configuration from 40. Arguments: NDSCaptureFlag = pOwner = pJobName = A pointer to return the default job configuration name. pJobRecord = A pointer to return the default job configuration. Return Value: SUCCESSFUL 0x0000 PS_ERR_BAD_VERSION 0x7770 PS_ERR_GETTING_DEFAULT 0x7773 PS_ERR_OPENING_DB 0x7774 PS_ERR_READING_DB 0x7775 PS_ERR_READING_RECORD 0x7776 PS_ERR_INTERNAL_ERROR 0x7779 PS_ERR_NO_DEFAULT_SPECIFIED 0x777B INVALID_CONNECTION 0x8801 ******************************************************************* --*/ unsigned int PS40JobRead( unsigned int NDSCaptureFlag, unsigned char *pOwner, unsigned char *pJobName, PPS_JOB_RECORD pJobRecord ) { return PS40GetJobName( NDSCaptureFlag, 0, pOwner, pJobName, pJobRecord, FALSE); } /*++ ******************************************************************* PS40GetJobName Routine Description: Common routine to get the print job configuration from 40. Arguments: NDSCaptureFlag = SearchFlag = pOwner = pJobName = A pointer to return the default job configuration name. pJobRecord = A pointer to return the default job configuration. GetDefault = TRUE = get the default job name, FALSE = Don't get the default job name. Return Value: SUCCESSFUL 0x0000 PS_ERR_BAD_VERSION 0x7770 PS_ERR_GETTING_DEFAULT 0x7773 PS_ERR_OPENING_DB 0x7774 PS_ERR_READING_DB 0x7775 PS_ERR_READING_RECORD 0x7776 PS_ERR_INTERNAL_ERROR 0x7779 PS_ERR_NO_DEFAULT_SPECIFIED 0x777B INVALID_CONNECTION 0x8801 ******************************************************************* --*/ unsigned int PS40GetJobName( unsigned int NDSCaptureFlag, unsigned short SearchFlag, unsigned char *pOwner, unsigned char *pJobName, PPS_JOB_RECORD pJobRecord, unsigned char GetDefault ) { unsigned char *pSearchJobName; unsigned long ObjectId; HANDLE stream = NULL; unsigned int Count; unsigned int Bytes; unsigned int RetCode = 0; unsigned int ConnectionNumber; JOB_NAME_AREA JobNameArea; JOB_RECORD_AREA JobRecord; PRINTCON_40_HEADER PrintConHeader; unsigned int Version40 = FALSE; unsigned int ConnectionHandle; unsigned char MailDirPath[NCP_MAX_PATH_LENGTH]; unsigned char TempJobName[33]; PBYTE JobContext = NULL; unsigned FileSize; // TRACKING Printer names can be used instead of queues // Must lookup "default print queue" if NT doesn't if ( NDSCaptureFlag ) { if ( !GetDefault ) { JobContext = strchr( pJobName, ':' ); if ( JobContext ) { *JobContext = '\0'; strncpy( TempJobName, pJobName, 32 ); TempJobName[32] = 0; *JobContext++ = ':'; pJobName = TempJobName; } } if ( JobContext ) { if (NDSfopenStream ( JobContext, "Print Job Configuration", &stream, &FileSize )) { RetCode = PS_ERR_OPENING_DB; goto CommonExit; } } else { if (NDSfopenStream ( TYPED_USER_NAME, "Print Job Configuration", &stream, &FileSize)) { PBYTE p; for ( p = TYPED_USER_NAME; p ; p = strchr ( p, '.' ) ) { p++; if ( *p == 'O' && *(p+1) == 'U' && *(p+2) == '=' ) break; if ( *p == 'O' && *(p+1) == '=' ) break; } if (NDSfopenStream ( p, "Print Job Configuration", &stream, &FileSize)) { RetCode = PS_ERR_OPENING_DB; goto CommonExit; } } } } else { if (!CGetDefaultConnectionID (&ConnectionHandle)) { RetCode = PS_ERR_OPENING_DB; goto CommonExit; } RetCode = GetConnectionNumber(ConnectionHandle, &ConnectionNumber); if (RetCode) { goto CommonExit; } RetCode = GetBinderyObjectID (ConnectionHandle, LOGIN_NAME, OT_USER, &ObjectId); if (RetCode) { goto CommonExit; } /** Build the path to open the file **/ sprintf(MailDirPath, "SYS:MAIL/%lX/PRINTJOB.DAT", SwapLong(ObjectId)); stream = CreateFileA( NTNWtoUNCFormat( MailDirPath ), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL ); if (stream == INVALID_HANDLE_VALUE) { sprintf(MailDirPath, "SYS:PUBLIC/PRINTJOB.DAT"); stream = CreateFileA( NTNWtoUNCFormat(MailDirPath), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL ); if (stream == INVALID_HANDLE_VALUE) { RetCode = PS_ERR_OPENING_DB; goto CommonExit; } } } if ( !ReadFile( stream, (PBYTE) &PrintConHeader, PRINTCON_40_HEADER_SIZE, &Bytes, NULL ) ) { RetCode = PS_ERR_INTERNAL_ERROR; goto CommonExit; } if (Bytes < PRINTCON_40_HEADER_SIZE) { if ( !( NDSCaptureFlag && Bytes) ) { RetCode = PS_ERR_INTERNAL_ERROR; goto CommonExit; } } /** Check the version number **/ if ( PrintConHeader.MajorVersion != 4 ) { RetCode = PS_ERR_BAD_VERSION; goto CommonExit; } if ( PrintConHeader.MinorVersion == 0 ) { Version40 = TRUE; } /** Get the name we are looking for **/ if (GetDefault) { if (PrintConHeader.DefaultJobName[0] == 0) { RetCode = PS_ERR_GETTING_DEFAULT; goto CommonExit; } pSearchJobName = PrintConHeader.DefaultJobName; } else { pSearchJobName = pJobName; } if ( !Version40 ) { SetFilePointer( stream, PRINTCON_41_HEADER_SIZE, NULL, FILE_BEGIN ); } Count = 0; /** Go through all of the job entry to look for the name **/ while (Count < PrintConHeader.NumberOfRecords) { if ( !ReadFile( stream, (PBYTE) &JobNameArea, JOB_NAME_AREA_SIZE, &Bytes, NULL) ) { RetCode = PS_ERR_INTERNAL_ERROR; goto CommonExit; } if (Bytes < JOB_NAME_AREA_SIZE) { if ( !( NDSCaptureFlag && Bytes) ) { RetCode = PS_ERR_INTERNAL_ERROR; goto CommonExit; } } Count++; /** Skip the entry with a null job name **/ if (JobNameArea.JobName[0] == 0) { continue; } /** Is this the job name we are looking for? **/ if (!_strcmpi(pSearchJobName, JobNameArea.JobName)) { break; } } /** See if we found the job name **/ if (Count > PrintConHeader.NumberOfRecords) { if (GetDefault) { RetCode = PS_ERR_GETTING_DEFAULT; } else { RetCode = PS_ERR_READING_RECORD; } goto CommonExit; } /* * The Job offset starts at the beginning of the third section. * The third section starts after the Header and after the * 50 record blocks. */ if ( Version40 ) { SetFilePointer( stream, PRINTCON_40_HEADER_SIZE + ( PrintConHeader.NumberOfBlocks * 50) * JOB_NAME_AREA_SIZE + JobNameArea.JobRecordOffset, NULL, FILE_BEGIN ); } else { SetFilePointer( stream, PRINTCON_41_HEADER_SIZE + ( PrintConHeader.NumberOfBlocks * 50) * JOB_NAME_AREA_SIZE + JobNameArea.JobRecordOffset, NULL, FILE_BEGIN ); } memset((PBYTE)&JobRecord, 0, sizeof(JobRecord)); if ( !ReadFile( stream, (PBYTE) &JobRecord, JOB_RECORD_AREA_SIZE, &Bytes, NULL) ) { RetCode = PS_ERR_READING_RECORD; goto CommonExit; } if (Bytes < JOB_RECORD_AREA_SIZE) { if ( !( NDSCaptureFlag && Bytes) ) { RetCode = PS_ERR_READING_RECORD; goto CommonExit; } } memset(pJobRecord, 0, PS_JOB_RECORD_SIZE); if (JobRecord.NotifyWhenDone) { pJobRecord->PrintJobFlag |= PS_JOB_NOTIFY; } if (JobRecord.BannerFlag) { pJobRecord->PrintJobFlag |= PS_JOB_PRINT_BANNER; } if (JobRecord.DataType) { pJobRecord->PrintJobFlag |= PS_JOB_EXPAND_TABS; } if (JobRecord.FormFeed) { pJobRecord->PrintJobFlag |= PS_JOB_NO_FORMFEED; } if (JobRecord.AutoEndCap) { pJobRecord->PrintJobFlag |= PS_JOB_AUTO_END; } if (JobRecord.TimeoutCount) { pJobRecord->PrintJobFlag |= PS_JOB_TIMEOUT; } if (JobRecord.Destination) { pJobRecord->PrintJobFlag |= PS_JOB_DS_PRINTER; } if ( JobRecord.SystemType ) { pJobRecord->PrintJobFlag |= PS_JOB_ENV_DS; } pJobRecord->Copies = JobRecord.NumberOfCopies; pJobRecord->TabSize = JobRecord.TabSize; pJobRecord->TimeOutCount = JobRecord.TimeoutCount; pJobRecord->LocalPrinter = JobRecord.LocalPrinter; strcpy(pJobRecord->Mode, JobRecord.Mode); strcpy(pJobRecord->Device, JobRecord.Device); strcpy(pJobRecord->FormName, JobRecord.FormName); strcpy(pJobRecord->BannerName, JobRecord.BannerName); if ( JobRecord.SystemType ) { ConvertUnicodeToAscii( JobRecord.u.DSObjectName ); strcpy(pJobRecord->u.DSObjectName, JobRecord.u.DSObjectName); } else { strcpy(pJobRecord->u.NonDS.PrintQueue, JobRecord.u.NonDS.QueueName); strcpy(pJobRecord->u.NonDS.FileServer, JobRecord.u.NonDS.Server); } if (GetDefault && pJobName) { strcpy(pJobName, JobNameArea.JobName); } if (pOwner) { *pOwner = 0; } CommonExit: if (stream != NULL) { // 07/19/96 cjc (Citrix code merge) // fclose causes a trap cause it expects *stream but // really should be using CloseHandle anyway. CloseHandle( stream ); // if ( NDSCaptureFlag ) // CloseHandle( stream ); // else // fclose( stream ); } return RetCode; }