/* * Printing interface for PuTTY. */ #include #include "putty.h" /* * Boggle. Flipping between the two branches of this #if appears to * make all the difference as to whether network printers show up * under PRINTER_ENUM_CONNECTIONS on NT 4. I don't pretend to * understand this... */ #if 0 #define ENUM_LEVEL 5 #define ENUM_PTR LPPRINTER_INFO_5 #define ENUM_TYPE PRINTER_INFO_5 #define ENUM_MEMBER pPrinterName #else #define ENUM_LEVEL 1 #define ENUM_PTR LPPRINTER_INFO_1 #define ENUM_TYPE PRINTER_INFO_1 #define ENUM_MEMBER pName #endif struct printer_enum_tag { int nprinters; ENUM_PTR info; }; struct printer_job_tag { HANDLE hprinter; }; static char *printer_add_enum(int param, char *buffer, int offset, int *nprinters_ptr) { DWORD needed, nprinters; buffer = srealloc(buffer, offset+512); /* * Exploratory call to EnumPrinters to determine how much space * we'll need for the output. Discard the return value since it * will almost certainly be a failure due to lack of space. */ EnumPrinters(param, NULL, ENUM_LEVEL, buffer+offset, 512, &needed, &nprinters); if (needed < 512) needed = 512; buffer = srealloc(buffer, offset+needed); if (EnumPrinters(param, NULL, ENUM_LEVEL, buffer+offset, needed, &needed, &nprinters) == 0) return NULL; *nprinters_ptr += nprinters; return buffer; } printer_enum *printer_start_enum(int *nprinters_ptr) { printer_enum *ret = smalloc(sizeof(printer_enum)); char *buffer = NULL, *retval; *nprinters_ptr = 0; /* default return value */ buffer = smalloc(512); retval = printer_add_enum(PRINTER_ENUM_LOCAL | PRINTER_ENUM_CONNECTIONS, buffer, 0, nprinters_ptr); if (!retval) goto error; else buffer = retval; ret->info = (ENUM_PTR)buffer; ret->nprinters = *nprinters_ptr; return ret; error: sfree(buffer); sfree(ret); *nprinters_ptr = 0; return NULL; } char *printer_get_name(printer_enum *pe, int i) { if (!pe) return NULL; if (i < 0 || i >= pe->nprinters) return NULL; return pe->info[i].ENUM_MEMBER; } void printer_finish_enum(printer_enum *pe) { if (!pe) return; sfree(pe->info); sfree(pe); } printer_job *printer_start_job(char *printer) { printer_job *ret = smalloc(sizeof(printer_job)); DOC_INFO_1 docinfo; int jobstarted = 0, pagestarted = 0; ret->hprinter = NULL; if (!OpenPrinter(printer, &ret->hprinter, NULL)) goto error; docinfo.pDocName = "PuTTY remote printer output"; docinfo.pOutputFile = NULL; docinfo.pDatatype = "RAW"; if (!StartDocPrinter(ret->hprinter, 1, (LPSTR)&docinfo)) goto error; jobstarted = 1; if (!StartPagePrinter(ret->hprinter)) goto error; pagestarted = 1; return ret; error: if (pagestarted) EndPagePrinter(ret->hprinter); if (jobstarted) EndDocPrinter(ret->hprinter); if (ret->hprinter) ClosePrinter(ret->hprinter); sfree(ret); return NULL; } void printer_job_data(printer_job *pj, void *data, int len) { DWORD written; if (!pj) return; WritePrinter(pj->hprinter, data, len, &written); } void printer_finish_job(printer_job *pj) { if (!pj) return; EndPagePrinter(pj->hprinter); EndDocPrinter(pj->hprinter); ClosePrinter(pj->hprinter); sfree(pj); }