#include "wxinc.h" #include #include #include #include "xvt.h" #include "xvtart.h" #ifdef __WXMSW__ #include "wx/dcps.h" #include "wx/msw/printdlg.h" #include "oswin32.h" #else #include "wx/setup.h" #include "wx/dcps.h" #include "oslinux.h" #include "incstr.h" #endif #include "xvtpdf.h" #include "xvtwin.h" #pragma pack(4) struct TPRINT_RCD : public PRINT_RCD { #ifdef __WXMSW__ unsigned char m_data[16*1024]; unsigned int m_size; // Dimensione della struct DEVMODE void SetData(void * data, unsigned int nSize); #else wxPrintNativeDataBase* m_data; unsigned int m_size; // Dimensione di wxPostScriptPrintNativeData void GetData(wxPrintNativeDataBase* data) const; void SetData(void * data); #endif unsigned int GetSize() const { return m_size; } TPRINT_RCD(); ~TPRINT_RCD(); }; #pragma pack() #ifdef __WXMSW__ void TPRINT_RCD::SetData(void* data, unsigned int nSize) { if (nSize <= sizeof(m_data)) { memset(m_data, 0, sizeof(m_data)); // Azzero per bene anche tutto quanto segue nSize memcpy(m_data, data, nSize); m_size = nSize; } else xvt_dm_post_error("Printer info exceeds 16K"); } TPRINT_RCD::TPRINT_RCD() : m_size(0) { pr = NULL; memset(m_data, 0, sizeof(m_data)); } TPRINT_RCD::~TPRINT_RCD() { memset(m_data, 0, sizeof(m_data)); m_size = 0; } #else void TPRINT_RCD::GetData(wxPrintNativeDataBase * data) const { memcpy(data, m_data, GetSize()); } void TPRINT_RCD::SetData(void* data) { memcpy(m_data, data, GetSize()); } wxNativePrintFactory __factory; TPRINT_RCD::TPRINT_RCD() { m_data = __factory.CreatePrintNativeData(); m_size = sizeof(*m_data); } TPRINT_RCD::~TPRINT_RCD() { delete m_data; } #endif /////////////////////////////////////////////////////////// // TwxPrintOut /////////////////////////////////////////////////////////// class TwxPrintOut : public wxPrintout { protected: const TPRINT_RCD* m_prcd; bool m_bBadDriver; virtual bool HasPage(int pageNum); virtual bool OnPrintPage(int pageNum); void ResetDC(); wxDC* CreateDC(const TPRINT_RCD* prcd, const char* title); public: void SetBadDriver(bool bd) { m_bBadDriver = bd; } bool HasBadDriver() const { return m_bBadDriver; } wxString PrinterName() const; bool IsPDF() const { return !HasBadDriver() && xvt_print_is_pdf(m_prcd) != 0; } bool InitDC(const TPRINT_RCD* prcd, const char* title); TwxPrintOut(const TPRINT_RCD* prcd = NULL); virtual ~TwxPrintOut() {} }; wxString TwxPrintOut::PrinterName() const { char strName[MAX_PATH] = ""; xvt_print_get_name(m_prcd, strName, sizeof(strName)); return wxString(strName); } bool TwxPrintOut::HasPage(int WXUNUSED(pageNum)) { return true; } bool TwxPrintOut::OnPrintPage(int WXUNUSED(pageNum)) { return false; } void TwxPrintOut::ResetDC() { wxDC* dc = GetDC(); if (dc != NULL) { delete dc; SetDC(NULL); } } static void RCD2data(const TPRINT_RCD* prcd, wxPrintData& data) { #ifdef WIN32 wxWindowsPrintNativeData ndb; ndb.SetDevMode(OsWin32_ConvertToNativePrinterInfo((void*)prcd->m_data, prcd->m_size)); ndb.TransferTo(data); // in assenza di PDEVNAMES aggiorno il nome in questo modo char strName[MAX_PATH] = ""; xvt_print_get_name(prcd, strName, sizeof(strName)); data.SetPrinterName(strName); #else prcd->GetData(data.GetNativeData()); data.ConvertFromNative(); #endif } static void data2RCD(const wxPrintData& data, TPRINT_RCD* prcd) { #ifdef WIN32 wxWindowsPrintNativeData* pNative = (wxWindowsPrintNativeData*)data.GetNativeData(); unsigned int nSize = 0; void* ptr = OsWin32_ConvertFromNativePrinterInfo(pNative->GetDevMode(), nSize); prcd->SetData(ptr, nSize); delete ptr; #else ((wxPrintData&)data).ConvertToNative(); prcd->SetData(data.GetNativeData()); #endif } wxDC* TwxPrintOut::CreateDC(const TPRINT_RCD* prcd, const char* title) { m_prcd = prcd; wxDC* dc = NULL; if (m_prcd == NULL) { wxPrinter printer; #ifdef WIN32 dc = new wxPrinterDC(printer.GetPrintDialogData().GetPrintData()); #else dc = new wxPostScriptDC(printer.GetPrintDialogData().GetPrintData()); #endif } else { wxPrintData data; RCD2data(prcd, data); const bool ispdf = IsPDF(); if (ispdf) dc = new TwxPDFDC(data, title); else #ifdef WIN32 dc = new wxPrinterDC(data); #else dc = new wxPostScriptDC(data); #endif } if (dc->IsOk()) { wxSize s = dc->GetPPI(); SetPPIPrinter(s.x, s.y); s = dc->GetSize(); SetPageSizePixels(s.x, s.y); SetDC(dc); wxWindow* pAbort = wxPrinterBase::sm_abortWindow; if (pAbort != NULL) { wxWindow* pStatic = pAbort->FindWindow(wxID_STATIC); if (pStatic != NULL) { wxString strPrompt; if (IsPDF()) { const wxFileName fn(title); strPrompt << wxT("Generazione di ") << fn.GetFullName(); } else strPrompt << wxT("Stampa su ") << PrinterName(); pStatic->SetLabel(strPrompt); } } } else { // delete dc; dc = NULL; } return dc; } bool TwxPrintOut::InitDC(const TPRINT_RCD* prcd, const char* title) { ResetDC(); wxDC* dc = CreateDC(prcd, title); if (dc != NULL) { wxSize s = dc->GetPPI(); if (s.x > 0) SetPPIPrinter(s.x, s.y); s = dc->GetSize(); if (s.x > 0) SetPageSizePixels(s.x, s.y); SetDC(dc); } m_bBadDriver = dc == NULL; return !m_bBadDriver; } TwxPrintOut::TwxPrintOut(const TPRINT_RCD* prcd) : wxPrintout(_GetAppTitle()), m_bBadDriver(false) { InitDC(prcd, _GetAppTitle()); } /////////////////////////////////////////////////////////// // TwxPrintOutCache /////////////////////////////////////////////////////////// class TwxPrintOutCache { unsigned long m_signature; TwxPrintOut* m_po; bool m_bLocked; protected: unsigned long Signature(const TPRINT_RCD* prcd) const; public: TwxPrintOut& Get(const TPRINT_RCD* prcd); void Reset(); void Lock() { m_bLocked = true; } void Unlock() { m_bLocked = false; } bool Ok() const { return m_po != NULL; } bool Locked() const { return m_bLocked; } bool Printing() const { return Ok() && Locked(); } TwxPrintOutCache(); ~TwxPrintOutCache(); } m_PrintoutCache; unsigned long TwxPrintOutCache::Signature(const TPRINT_RCD* prcd) const { unsigned long h = 0; if (prcd != NULL) { const unsigned char* data = (const unsigned char*)prcd; const size_t sz = prcd->GetSize(); for (size_t c = 0; c < sz; c++) { h = (h << 2) + data[c]; const unsigned long i = h & 0xC0000000; if (i) h = (h ^ (i >> 12)) & 0x3FFFFFFF; } } return h; } void TwxPrintOutCache::Reset() { wxASSERT(!Locked()); if (m_po != NULL) { delete m_po; m_po = NULL; } } TwxPrintOut& TwxPrintOutCache::Get(const TPRINT_RCD* prcd) { if (!Locked()) { if (prcd == NULL) { if (m_po == NULL) m_po = new TwxPrintOut; } else { unsigned long signature = Signature(prcd); if (m_po != NULL && m_signature == signature) return *m_po; Reset(); m_po = new TwxPrintOut(prcd); m_signature = signature; } } wxASSERT(m_po != NULL); return *m_po; } TwxPrintOutCache::TwxPrintOutCache() : m_signature(0), m_po(NULL) { } TwxPrintOutCache::~TwxPrintOutCache() { // Reset(); // Essendo un oggetto statico la delete m_po non funziona! } /////////////////////////////////////////////////////////// // TPrintDC /////////////////////////////////////////////////////////// // Flag di reset ad inizio pagina bool TPrintDC::_page_start = false; void TPrintDC::SetPageStart() { _page_start = true; } wxDC& TPrintDC::GetDC(bool) { _dc = m_PrintoutCache.Get(NULL).GetDC(); // Forza display context corrente if (_page_start) { _dirty = -1; _page_start = false; } return TDC::GetDC(false); } void TPrintDC::KillDC() { _dc = NULL; // _dc is owned by wxPrintout } TPrintDC::TPrintDC(wxWindow* owner) : TDC(owner) { _page_start = false; } TPrintDC::~TPrintDC() { KillDC(); } /////////////////////////////////////////////////////////// // Printing management :-((((( /////////////////////////////////////////////////////////// BOOLEAN xvt_app_escape(int esc_code, PRINT_RCD* rcd, long* ph, long* pw, long* pvr, long* phr) { switch (esc_code) { case XVT_ESC_GET_PRINTER_INFO: if (ph) *ph = *pw = 0; if (pvr) *pvr = *phr = 0; if (rcd == NULL || xvt_print_is_valid(rcd)) { const TwxPrintOut& po = m_PrintoutCache.Get((TPRINT_RCD*)rcd); int w, h; if (ph) { po.GetPageSizePixels(&w, &h); *pw = w; *ph = h; } if (pvr) { po.GetPPIPrinter(&w, &h); *phr = w; *pvr = h; } return TRUE; } break; case XVT_ESC_SET_PRINTER_INFO: if (xvt_print_is_valid(rcd) && ph != NULL && pw != NULL) { TPRINT_RCD* prcd = (TPRINT_RCD*)rcd; wxPrintData data; RCD2data(prcd, data); data.SetOrientation(*ph > *pw ? wxPORTRAIT : wxLANDSCAPE); data.ConvertToNative(); data2RCD(data, prcd); TwxPrintOut& po = m_PrintoutCache.Get((TPRINT_RCD*)rcd); po.InitDC(prcd, _GetAppTitle()); return true; } break; default: break; } return FALSE; } BOOLEAN xvt_dm_post_page_setup(PRINT_RCD* precp) { wxPageSetupDialog dlg((wxWindow*)TASK_WIN); TPRINT_RCD* rcd = (TPRINT_RCD*)precp; wxPageSetupData& pdd = dlg.GetPageSetupData(); wxPrintData& data = pdd.GetPrintData(); RCD2data(rcd, data); pdd.EnableMargins(false); const BOOLEAN ok = dlg.ShowModal() == wxID_OK; if (ok) { data2RCD(data, rcd); m_PrintoutCache.Reset(); } return ok; } void xvt_dwin_draw_image_on_pdf(WINDOW win, const char* name, RCT* dest) { wxASSERT(win == PRINTER_WIN); const wxRect dst = RCT2Rect(dest); TwxPDFDC& dc = *wxStaticCast(&GetTDCMapper().GetDC(win), TwxPDFDC); dc.DrawImage(name, dst); } long xvt_fmap_get_family_sizes(PRINT_RCD *precp, char *family, long *size_array, BOOLEAN *scalable, long max_sizes) { long size = 0; *scalable = FALSE; #ifdef WIN32 if (xvt_print_is_valid(precp)) { const TwxPrintOut& po = m_PrintoutCache.Get((TPRINT_RCD*)precp); if (!po.HasBadDriver()) size = OsWin32_EnumerateSizes(po.GetDC()->GetHDC(), family, size_array, scalable, max_sizes); } else { size = OsWin32_EnumerateSizes(NULL, family, size_array, scalable, max_sizes); } #else size = OsLinux_EnumerateSizes(family, size_array, scalable, max_sizes); #endif return size; } long xvt_fmap_get_families(PRINT_RCD *precp, char **family_array, long max_families) { long size = 0; family_array[0] = NULL; #ifdef WIN32 if (xvt_print_is_valid(precp)) { TwxPrintOut& po = m_PrintoutCache.Get((TPRINT_RCD*)precp); if (!po.HasBadDriver()) { size = OsWin32_EnumerateFamilies(po.GetDC()->GetHDC(), family_array, max_families); if (size == 0) po.SetBadDriver(true); } } else { wxFrame* tw = (wxFrame*)TASK_WIN; wxClientDC dc(tw); size = OsWin32_EnumerateFamilies(dc.GetHDC(), family_array, max_families); } #else size = OsLinux_EnumerateFamilies(family_array, max_families); #endif return size; } void xvt_print_close(void) { // Nothing to do ? } BOOLEAN xvt_print_close_page(PRINT_RCD* precp) { BOOLEAN ok = m_PrintoutCache.Printing(); if (ok) { const TwxPrintOut& po = m_PrintoutCache.Get(NULL); wxDC* dc = po.GetDC(); dc->EndPage(); /* #ifdef __WXMSW__ TPRINT_RCD* prcd = (TPRINT_RCD*)precp; if (OsWin32_IsGenericTextOnly(prcd->m_data)) OsWin32_SpoolNewLine((unsigned int)dc->GetHDC()); #endif */ } return ok; } PRINT_RCD* xvt_print_create(int *sizep) { return xvt_print_create_by_name(sizep, NULL); } // Impone il nome ad un PRINT_RCD. // Utilizzato per la definiz. della stamp. virtuale PDF predefinita int xvt_print_set_name(PRINT_RCD* precp, const char* name) { if (precp == NULL) return 0; if (!name || !*name) return 0; wxString n = name; #ifdef WIN32 wxStrncpy(((char*)precp) + 4, name, 32); #else TPRINT_RCD* rcd = (TPRINT_RCD*)precp; wxPrintData data; rcd->GetData(data); data.SetPrinterName(n); rcd->SetData(data); #endif return n.Length(); } // Nuova funzione inventata da Aga PRINT_RCD* xvt_print_create_by_name(int* sizep, const char* name) { TPRINT_RCD* pr = NULL; *sizep = 0; const bool ispdf = name != NULL && xvt_str_compare_ignoring_case(name, XVT_PDF_PRINTER_NAME) == 0; if (ispdf) name = NULL; #ifdef WIN32 void* data = OsWin32_GetPrinterInfo(*sizep, name); if (data != NULL) { pr = new TPRINT_RCD; pr->SetData(data, *sizep); *sizep += 4; // Spazio per puntatore iniziale delete data; } #else wxPrintData data; data.SetPrinterName(name == NULL ? "" : name); pr = new TPRINT_RCD; data2RCD(data, pr); *sizep = pr->GetSize(); #endif if (ispdf) xvt_print_set_name(pr, XVT_PDF_PRINTER_NAME); return pr; } WINDOW xvt_print_create_win(PRINT_RCD* precp, const char* title) { bool ok = xvt_print_is_valid(precp) != FALSE; if (ok) { TPRINT_RCD* rcd = (TPRINT_RCD*)precp; if (m_PrintoutCache.Printing()) { TwxPrintOut& po = m_PrintoutCache.Get(NULL); ok = po.InitDC(rcd, title); if (ok) { po.OnBeginPrinting(); po.OnBeginDocument(1, 32000); } } else { TwxPrintOut& po = m_PrintoutCache.Get(rcd); ok = po.InitDC(rcd, title); } } return ok ? PRINTER_WIN : NULL_WIN; } void xvt_print_destroy(PRINT_RCD* precp) { if (precp != NULL) delete precp; } RCT* xvt_print_get_next_band(void) { static bool yes = false; static RCT rct; yes = !yes; if (!yes) return NULL; const TwxPrintOut& po = m_PrintoutCache.Get(NULL); int w, h; po.GetPageSizePixels(&w, &h); rct.left = rct.top = 0; rct.right = w; rct.bottom = h; return &rct; } BOOLEAN xvt_print_is_pdf(const PRINT_RCD* precp) { char strName[MAX_PATH]; xvt_print_get_name(precp, strName, sizeof(strName)); return xvt_str_compare_ignoring_case(strName, XVT_PDF_PRINTER_NAME) == 0; } BOOLEAN xvt_print_pdf_version(char* version, int size) { const BOOLEAN ok = version && size > 12; if (ok) { wxString str = "PDFlib "; str += PDFLIB_VERSIONSTRING; wxStrncpy(version, str, size); } return ok; } BOOLEAN xvt_print_is_valid(const PRINT_RCD* precp) { BOOLEAN ok = precp != NULL && precp->pr == NULL; if (ok) { const TPRINT_RCD* rcd = (const TPRINT_RCD*)precp; #ifdef __WXMSW__ ok = OsWin32_CheckPrinterInfo(rcd->m_data, rcd->m_size); #else wxPrintData data; RCD2data(rcd, data); ok = data.Ok(); #endif } return ok; } int xvt_print_get_name(const PRINT_RCD* precp, char* name, int sz_s) { if (!xvt_print_is_valid(precp)) return 0; #ifdef __WXMSW__ wxString n = ((const char*)precp) + 4; if (n.Length() >= 30) { double dBest = 0.0; wxString strBest = n; SLIST plist = xvt_print_list_devices(); for (SLIST_ELT pitem = xvt_slist_get_first(plist); pitem != NULL; pitem = xvt_slist_get_next(plist, pitem)) { const char* pname = xvt_slist_get(plist, pitem, NULL); const double dScore = xvt_str_fuzzy_compare_ignoring_case(n, pname); if (dScore > dBest) { dBest = dScore; strBest = pname; if (dScore >= 1.0) break; } } xvt_slist_destroy(plist); n = strBest; } #else TPRINT_RCD* rcd = (TPRINT_RCD*)precp; wxPrintData data; RCD2data(rcd, data); wxString n = data.GetPrinterName(); #endif if (name != NULL && sz_s > 0) { wxStrncpy(name, n, sz_s); name[sz_s-1] = '\0'; } return n.Length(); } BOOLEAN xvt_print_open(void) { return m_PrintoutCache.Ok(); } /////////////////////////////////////////////////////////// class TwxPrintAbortDialog : public wxPrintAbortDialog { public: void Pulse(); TwxPrintAbortDialog(); }; void TwxPrintAbortDialog::Pulse() { wxGauge* pGauge = wxStaticCast(FindWindow(wxID_FORWARD), wxGauge); pGauge->Pulse(); } TwxPrintAbortDialog::TwxPrintAbortDialog() : wxPrintAbortDialog(NULL, _("Stampa"), wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE) { wxBoxSizer *button_sizer = new wxBoxSizer( wxVERTICAL ); button_sizer->Add(new wxStaticText(this, wxID_STATIC, _("Stampa in corso..."), wxDefaultPosition, wxSize(480,-1)), 0, wxALL, 10 ); button_sizer->Add(new wxGauge(this, wxID_FORWARD, 1, wxDefaultPosition, wxSize(480,-1)), 0, wxALL, 10 ); //button_sizer->Add(new wxButton(this, wxID_CANCEL, wxT("Annulla") ), 0, wxALL | wxALIGN_CENTER, 10 ); button_sizer->Add(new wxBitmapButton(this, wxID_CANCEL, xvtart_GetToolResource(102,32) ), 0, wxALL | wxALIGN_CENTER, 10 ); SetAutoLayout(true); SetSizer(button_sizer); button_sizer->Fit(this); button_sizer->SetSizeHints(this); Show(); Update(); } void CreateAbortWindow() { wxPrinterBase::sm_abortWindow = new TwxPrintAbortDialog; } void DestroyAbortWindow() { if (wxPrinterBase::sm_abortWindow != NULL) { wxPrinterBase::sm_abortWindow->Hide(); delete wxPrinterBase::sm_abortWindow; wxPrinterBase::sm_abortWindow = NULL; } } /////////////////////////////////////////////////////////// BOOLEAN xvt_print_start_thread(BOOLEAN(*print_fcn)(long), long data) { const wxString strDir = ::wxGetCwd(); // Memorizzo la directory corrente (Acrobat la cambia) wxBeginBusyCursor(); m_PrintoutCache.Reset(); // Forza nuovo contesto di stampa TwxPrintOut& po = m_PrintoutCache.Get(NULL); m_PrintoutCache.Lock(); wxEndBusyCursor(); CreateAbortWindow(); const BOOLEAN success = print_fcn(data); DestroyAbortWindow(); if (!po.HasBadDriver()) { po.OnEndDocument(); po.OnEndPrinting(); } m_PrintoutCache.Unlock(); m_PrintoutCache.Reset(); ::wxSetWorkingDirectory(strDir); // Ripristino la directory corrente (Acrobat l'ha cambiata) return success; } BOOLEAN xvt_print_suspend_thread() { BOOLEAN ok = m_PrintoutCache.Printing(); if (ok) { TwxPrintOut& po = m_PrintoutCache.Get(NULL); po.OnEndDocument(); // Sembra generare una pagina vuota indesiderata po.OnEndPrinting(); } return ok; } BOOLEAN xvt_print_restart_thread() { TwxPrintOut& po = m_PrintoutCache.Get(NULL); po.OnBeginPrinting(); po.OnBeginDocument(1, 32000); return TRUE; } BOOLEAN xvt_print_open_page(PRINT_RCD* WXUNUSED(precp)) { BOOLEAN ok = m_PrintoutCache.Printing(); if (ok) { if (wxPrinterBase::sm_abortIt) ok = FALSE; else { TwxPrintOut& po = m_PrintoutCache.Get(NULL); po.GetDC()->StartPage(); TPrintDC::SetPageStart(); // Flag per azzeramento dati DC // Aggiorna barra di attesa TwxPrintAbortDialog* pad = wxDynamicCast(wxPrinterBase::sm_abortWindow, TwxPrintAbortDialog); if (pad != NULL) { pad->Pulse(); wxWakeUpIdle(); } } } return ok; } /////////////////////////////////////////////////////////// // Added by XVAGA /////////////////////////////////////////////////////////// #ifdef LINUX static const char * cups_file = "/etc/cups/printers.conf"; static const char * cups_local_file = "./printers.conf"; static const char * prcap_local_file = "./printcap"; static bool is_cups() { static int printer_system = -1; if (printer_system < 0) printer_system = xvt_fsys_file_exists(cups_file) ? 1 : 2; return printer_system == 1; } #endif SLIST xvt_print_list_devices() { SLIST list = xvt_slist_create(); #ifdef WIN32 const DWORD dwFlags = PRINTER_ENUM_LOCAL | PRINTER_ENUM_CONNECTIONS; const int level = xvt_sys_get_os_version() >= XVT_WS_WIN_NT ? 4 : 5; DWORD dwSize = 0, dwPrinters = 0; ::EnumPrinters (dwFlags, NULL, level, NULL, 0, &dwSize, &dwPrinters); if (dwSize > 0) { BYTE* pBuffer = new BYTE[dwSize]; ::EnumPrinters (dwFlags, NULL, level, pBuffer, dwSize, &dwSize, &dwPrinters); if (level == 4) { const PRINTER_INFO_4* pPrnInfo = (const PRINTER_INFO_4*)pBuffer; for (UINT i=0; i < dwPrinters; i++) { xvt_slist_add_at_elt(list, NULL, pPrnInfo->pPrinterName, NULL); pPrnInfo++; } } else { const PRINTER_INFO_5* pPrnInfo = (const PRINTER_INFO_5*)pBuffer; for (UINT i=0; i < dwPrinters; i++) { xvt_slist_add_at_elt(list, NULL, pPrnInfo->pPrinterName, NULL); pPrnInfo++; } } delete[] pBuffer; } #else if (is_cups()) { ifstream p(cups_local_file); char line[4096]; const char * str_to_find = "Printer"; while (p.getline(line, sizeof(line))) { char * s; if (line[0] == '<' && line[1] != '/' && (s = strstr(line, str_to_find)) != NULL) { s += strlen(str_to_find); while (isspace(*s)) s++; if (*s) { char * l = s + strlen(s) - 1; while (*l == '>' || isspace(*l)) l--; *(l + 1) = '\0'; xvt_slist_add_at_elt(list, NULL, s, 0L); } } } } else { ifstream p(prcap_local_file); // vedere char line[4096]; while (p.getline(line, sizeof(line))) { if (line[0] != '#') { const int len = strlen(line); int i; for (i = 0; i < len; i++) { const char c = line[i]; if (!(isalpha(c) || isdigit(c) || isblank(c))) break; } line[i] = '\0'; xvt_slist_add_at_elt(list, NULL, line, 0L); } } } #endif return list; } BOOLEAN xvt_print_set_default_device(const char* name) { BOOLEAN ok = name != NULL && *name > ' '; #ifdef WIN32 if (ok) { wxString pdev(name); if (pdev.Find(',') < 0) { char szDevice[256]; ::GetProfileString ("devices", pdev, "", szDevice, sizeof(szDevice)); pdev << ',' << szDevice; } ok = ::WriteProfileString("windows", "device", pdev) != 0; } #endif return ok; } BOOLEAN xvt_print_get_default_device(char* name, int namesize) { bool ok = FALSE; #ifdef __WXMSW__ ok = ::GetProfileString ("windows", "device", ",,,", name, namesize) != 0; #else *name = '\0'; if (is_cups()) { ifstream p(cups_local_file); char line[4096]; const char * str_to_find = "' || isspace(*l)) l--; *(l + 1) = '\0'; strcpy(name, s); } ok = TRUE; } } } #endif return ok; } /////////////////////////////////////////////////////////// // Gestione files di configurazione /////////////////////////////////////////////////////////// int xvt_fsys_get_campo_stp_value(const char* name, char* value, int valsize) { BOOLEAN bFound = FALSE; #ifdef __WXMSW__ const char* const stpfile = "c:/campo.stp"; int p; DIRECTORY dir; char exedir[_MAX_PATH], path[_MAX_PATH]; xvt_fsys_get_default_dir(&dir); xvt_fsys_convert_dir_to_str(&dir, exedir, sizeof(exedir)); for (p = 1; ; p++) { char para[4]; sprintf(para, "%d", p); int len = xvt_sys_get_profile_string(stpfile, para, "Program", "", path, sizeof(path)); if (len <= 0) break; if (wxEndsWithPathSeparator(path)) { len--; path[len] = '\0'; } if (xvt_str_compare_ignoring_case(path, exedir) == 0) { xvt_sys_get_profile_string(stpfile, para, name, "", value, valsize); bFound = *value > ' '; break; } } #endif return bFound; } /* @($) CGetCampoIni FILES @(ID) Restituisce il nome del file che contiene il prefisso corrente. @(FD) @(ISV) s,s1 = stringhe di lavoro. Versione WIN32 e LINUX. @(FSV) */ const char* xvt_fsys_get_campo_ini() { static wxString prawin; if (prawin.IsEmpty()) { BOOLEAN bFound = FALSE; char exedir[_MAX_PATH], path[_MAX_PATH]; // Nelle installazioni sfigate con programmi in rete cerca di stabilire il percorso locale di Campo.ini DIRECTORY dir; xvt_fsys_get_default_dir(&dir); xvt_fsys_convert_dir_to_str(&dir, exedir, sizeof(exedir)); #ifdef WIN32 if (xvt_fsys_is_network_drive(exedir)) bFound = xvt_fsys_get_campo_stp_value("CampoIni", path, sizeof(path)); if (!bFound) { if (OsWin32_IsWindowsServer()) { xvt_fsys_build_pathname(path, NULL, wxGetHomeDir(), "campo", "ini", NULL); bFound = xvt_fsys_file_exists(path); if (!bFound) { char pathstd[_MAX_PATH]; xvt_fsys_build_pathname(pathstd, NULL, exedir, "campo", "ini", NULL); if (xvt_fsys_file_exists(pathstd)) wxCopyFile(pathstd, path); } } } if (!bFound) xvt_fsys_build_pathname(path, NULL, exedir, "campo", "ini", NULL); #else if (!bFound) { char username[32]; char ininame[_MAX_FNAME]; xvt_sys_get_user_name(username, sizeof(username)); if (xvt_str_compare_ignoring_case(username, "root") == 0) *username = '\0'; sprintf(ininame, "campo%s", username); xvt_fsys_build_pathname(path, NULL, exedir, ininame, "ini", NULL); if (!xvt_fsys_file_exists(path) && *username > ' ') { char pathstd[_MAX_PATH]; xvt_fsys_build_pathname(pathstd, NULL, exedir, "campo", "ini", NULL); if (xvt_fsys_file_exists(pathstd)) wxCopyFile(pathstd, path); } } #endif if (!xvt_fsys_file_exists(path)) { char msg[_MAX_PATH]; sprintf(msg, _("Impossibile aprire '%s'"), path); xvt_dm_post_fatal_exit(msg); } prawin = path; } return prawin; } /////////////////////////////////////////////////////////// // Gestione MD5 /////////////////////////////////////////////////////////// #include "MD5Checksum.h" BOOLEAN xvt_str_md5(const char* instr, char* outstr) { wxASSERT(outstr != NULL); BOOLEAN ok = instr && *instr && outstr; if (ok) { wxStrcpy(outstr, wxMD5Checksum::GetMD5((unsigned char*)instr, strlen(instr))); ok = *outstr != '\0'; } return ok; } BOOLEAN xvt_fsys_file_md5(const char* path, char* outstr) { wxASSERT(outstr != NULL); BOOLEAN ok = path && *path && outstr; if (ok) { wxStrcpy(outstr, wxMD5Checksum::GetMD5(wxString(path))); ok = *outstr != '\0'; } return ok; } /////////////////////////////////////////////////////////// // Gestione firma digitale /////////////////////////////////////////////////////////// class TwxSignatureDlg : public wxDialog { private: virtual bool TransferDataToWindow(); virtual bool TransferDataFromWindow(); protected: wxTextCtrl* AddString(wxSizer* ctlSizer, int id, const char* label, wxString* str, int nFlags = 0); public: wxString m_strUser, m_strPIN; bool m_bMark; TwxSignatureDlg(); }; bool TwxSignatureDlg::TransferDataToWindow() { FindWindowById(1001, this)->SetLabel(m_strUser); // FindWindowById(1002, this)->SetLabel(m_strPin); // Non riproporre wxCheckBox* cb = wxStaticCast(FindWindowById(1003, this), wxCheckBox); cb->SetValue(m_bMark); return true; } bool TwxSignatureDlg::TransferDataFromWindow() { m_strUser = FindWindowById(1001, this)->GetLabel(); m_strPIN = FindWindowById(1002, this)->GetLabel(); wxCheckBox* cb = wxStaticCast(FindWindowById(1003, this), wxCheckBox); m_bMark = cb->IsEnabled() && cb->GetValue(); return !m_strUser.IsEmpty() && !m_strPIN.IsEmpty(); } wxTextCtrl* TwxSignatureDlg::AddString(wxSizer* ctlSizer, int id, const char* label, wxString* str, int nFlags) { wxStaticText* lbl = new wxStaticText(this, wxID_ANY, label); wxTextCtrl* txt = new wxTextCtrl(this, id, wxEmptyString, wxDefaultPosition, wxSize(120, -1), nFlags, wxTextValidator(wxFILTER_ASCII, str)); ctlSizer->Add(lbl, 0, wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL | wxALL, 4); ctlSizer->Add(txt, 1, wxALIGN_LEFT | wxALL, 4); return txt; } TwxSignatureDlg::TwxSignatureDlg() : wxDialog(NULL, wxID_ANY, "ESigner", wxDefaultPosition) { wxSizer* ctlSizer = new wxFlexGridSizer(4, 2, 4, 4); AddString(ctlSizer, 1001, "Utente", &m_strUser); AddString(ctlSizer, 1002, "PIN", &m_strPIN, wxTE_PASSWORD); wxCheckBox* ctlMark = new wxCheckBox(this, 1003, "Marcatura temporale"); if (xvt_net_get_status() <= 0) ctlMark->Disable(); ctlSizer->AddSpacer(4); ctlSizer->Add(ctlMark, 0, wxALIGN_LEFT | wxALL, 4); wxSizer* ctlButtonSizer = CreateButtonSizer(wxOK | wxCANCEL); wxBoxSizer* ctlTopSizer = new wxBoxSizer(wxVERTICAL); ctlTopSizer->Add(ctlSizer, 0, wxALIGN_CENTER); ctlTopSizer->Add(ctlButtonSizer, 0, wxALIGN_CENTER); SetSizer(ctlTopSizer); ctlTopSizer->SetSizeHints(this); } typedef int (*dllSignMethod) ( char *operation, //operazione : S (firma file), // S+D (firma directory), // S+T (firma + marca file), // S+T+D (firma + marca directory) char *method, //metodo : F (file cert), P (file PFX), T (token/smartcard) char *inputFile, //percorso file di input char *outputFile, //percorso file di output (senza estensione) char *timestampOutputFile, //percorso file di output TSR (marca temporale separata) char *extension, //estensione in caso di input PDF char *certificateFile, //nome file .cer o .crt contenente il certificato char *kprivFile, //nome file .pem contenente la chiave privata char *pfxFile, //nome file pfx contenente certificato e chiave privata char *pkcs11Dll, //nome dll PKCS11 char *pin_passphrase, //passphrase o PIN (per chiave privata, pfx o token) char *directoryTokenCache, //directory cache certificati estratti da token char *indexCertificateOnToken, //numero certificato del token char *tsaURI, //URI della TSA (http:\\....) char *tsaUsername, //Username TSA char *tsaPassword, //Password TSA char *tsaPolicy, //Policy TSA char *tsaCoding, //Codifica TSA: binary o base64 char *rootCADir) //percorso directory contenente i certificati della rootca ; typedef int (*dllVerifyMethod) ( char *operation, //operazione : V (verifica file), // V+D (verifica directory), char *inputFileName, //percorso file di input char *responseFileName, //percorso file di esito char *rootCADir, //percorso directory contenente i certificati della rootca char *rootTSADir, //percorso directory contenente i certificati delle rootTSA char *resultDescription //parametro di output contenente l'esito della verifica ); class TEsigner { #ifdef WIN32 HMODULE m_hESigner; dllSignMethod _SignPDF; dllVerifyMethod _VerifyPDF; #endif wxString m_strUser, m_strPin, m_strDllFile, m_strCertificate; wxString m_strTSAuri, m_strTSAuser, m_strTSApwd, m_strPolicy, m_strTSAcoding; bool m_bMark; public: bool Init(bool on); bool Sign(const wxString& strInput, wxString& strOutput); bool Verify(const wxString& strInput); TEsigner(); ~TEsigner(); } __TheSigner; TEsigner::TEsigner() : m_bMark(false) #ifdef WIN32 , m_hESigner(NULL), _SignPDF(NULL), _VerifyPDF(NULL) #endif {} TEsigner::~TEsigner() { Init(false); } bool TEsigner::Init(bool bLoad) { bool ok = false; #ifdef WIN32 if (bLoad) { char str[_MAX_PATH] = ""; xvt_sys_get_profile_string(NULL, NULL, "Study", "", str, sizeof(str)); wxString strConfig; strConfig = str; if (!wxEndsWithPathSeparator(strConfig)) strConfig << wxFILE_SEP_PATH; strConfig << "config" << wxFILE_SEP_PATH << wxGetHostName() << ".ini"; if (m_hESigner == NULL) { m_hESigner = ::LoadLibrary("esigner.dll"); if (m_hESigner != NULL) { _SignPDF = (dllSignMethod)::GetProcAddress(m_hESigner, "Sign"); _VerifyPDF = (dllVerifyMethod)::GetProcAddress(m_hESigner, "Verify"); m_strPin.Empty(); TwxSignatureDlg dlg; if (m_strUser.IsEmpty()) m_strUser = wxGetUserId(); dlg.m_strUser = m_strUser; dlg.m_bMark = m_bMark; if (dlg.ShowModal() == wxID_OK) { m_strUser = dlg.m_strUser; m_strPin= dlg.m_strPIN; m_bMark = dlg.m_bMark; } else return ok = false; xvt_sys_get_profile_string(strConfig, "fd", "Cert_"+m_strUser, "", str, sizeof(str)); if (*str == '\0') // Se non trova l'utente corrente di riprova con Guest xvt_sys_get_profile_string(strConfig, "fd", "Cert_Guest", "", str, sizeof(str)); wxStringTokenizer strDllCert(str, ","); m_strDllFile = strDllCert.GetNextToken(); m_strDllFile.MakeLower(); m_strCertificate = strDllCert.GetNextToken(); if (m_strCertificate.IsEmpty() && m_strDllFile.EndsWith(".dll")) m_strCertificate = "0"; if (m_bMark) { m_strTSAuri = strDllCert.GetNextToken(); m_strTSAuser = strDllCert.GetNextToken(); m_strTSApwd = strDllCert.GetNextToken(); m_strPolicy = strDllCert.GetNextToken(); m_strTSAcoding = strDllCert.GetNextToken(); if (m_strTSAcoding.IsEmpty()) m_strTSAcoding = wxT("binary"); if (m_strTSAuri.IsEmpty()) { wxString msg; msg << "Mancano i parametri per la marcatura temporale" << "\nControllare Cert_" << m_strUser << " nel paragrafo [fd]\ndel file " << strConfig; xvt_dm_post_warning(msg); m_bMark = false; } } } } ok = m_hESigner != NULL && _SignPDF != NULL && _VerifyPDF != NULL; if (ok) { ok = wxFileExists(m_strDllFile); if (!ok) { wxString msg; msg << "Impossibile caricare il certificato/driver " << m_strDllFile << "\nControllare Cert_" << m_strUser << " nel paragrafo [fd]\ndel file " << strConfig; xvt_dm_post_error(msg); } } else xvt_dm_post_error("Impossibile caricare 'ESigner.dll'"); } else { if (m_hESigner != NULL) { ::FreeLibrary(m_hESigner); m_hESigner = NULL; _SignPDF = NULL; _VerifyPDF = NULL; m_strPin.Empty(); } } #endif return ok; } bool TEsigner::Sign(const wxString& strInput, wxString& strOutput) { if ((m_strPin.IsEmpty() || m_strDllFile.IsEmpty()) && !Init(true)) return false; const char* ext = strInput.Lower().EndsWith(".pdf") ? ".pdf.p7m" : ""; if (strOutput.IsEmpty()) strOutput = strInput + ".p7m"; ::wxRemoveFile(strOutput); // Altrimenti la fantastica dll s'incazza come una biscia const wxString strFile = strOutput.BeforeFirst('.'); int res = 0; if (m_strDllFile.Lower().EndsWith(".dll")) { if (m_bMark && !m_strTSAuri.IsEmpty()) // Firma con marcatura temporale { res = _SignPDF("S", "T", // "S"ignature with "T"oken or smartcard (char*)(const char*)strInput, (char*)(const char*)strFile, NULL, (char*)ext, NULL, NULL, NULL, (char*)(const char*)m_strDllFile, (char*)(const char*)m_strPin, NULL, (char*)(const char*)m_strCertificate, (char*)(const char*)m_strTSAuri, (char*)(const char*)m_strTSAuser, (char*)(const char*)m_strTSApwd, (char*)(const char*)m_strPolicy, (char*)(const char*)m_strTSAcoding, NULL); } else // Firma normale { res = _SignPDF("S", "T", // "S"ignature with "T"oken or smartcard (char*)(const char*)strInput, (char*)(const char*)strFile, NULL, (char*)ext, NULL, NULL, NULL, (char*)(const char*)m_strDllFile, (char*)(const char*)m_strPin, NULL, (char*)(const char*)m_strCertificate, NULL, NULL, NULL, NULL, NULL, NULL); } } else { if (m_bMark && !m_strTSAuri.IsEmpty()) // Firma con marcatura temporale { res = _SignPDF("S", "P", // "S"ignature with "P"fx file (char*)(const char*)strInput, (char*)(const char*)strFile, NULL, (char*)ext, NULL, NULL, (char*)(const char*)m_strDllFile, NULL, (char*)(const char*)m_strPin, NULL, NULL, (char*)(const char*)m_strTSAuri, (char*)(const char*)m_strTSAuser, (char*)(const char*)m_strTSApwd, (char*)(const char*)m_strPolicy, (char*)(const char*)m_strTSAcoding, NULL); } else { res = _SignPDF("S", "P", // "S"ignature with "P"fx file (char*)(const char*)strInput, (char*)(const char*)strFile, NULL, (char*)ext, NULL, NULL, (char*)(const char*)m_strDllFile, NULL, (char*)(const char*)m_strPin, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL); } } if (res == 0) { if (!xvt_fsys_file_exists(strOutput)) { wxString str = "ESigner.dll can't create " + strOutput; xvt_dm_post_error(str); res = -1; } } else { wxString str; str.Printf("ESigner.dll error %d", res); xvt_dm_post_error(str); } return res == 0; } bool TEsigner::Verify(const wxString& strInput) { int res = -1; if (Init(!strInput.IsEmpty())) { char file[_MAX_PATH], result[_MAX_PATH]; wxStrncpy(file, strInput, _MAX_PATH); res = _VerifyPDF("V", file, NULL, NULL, NULL, result); } return res == 0; } BOOLEAN xvt_sign_start() { return __TheSigner.Init(true); } BOOLEAN xvt_sign_stop() { __TheSigner.Init(false); return TRUE; } BOOLEAN xvt_sign_file(const char* input_name, char* output_name) { wxString strInput = input_name, strOutput = output_name; if (strInput.IsEmpty()) { FILE_SPEC fs; xvt_fsys_convert_str_to_fspec(strInput, &fs); if (xvt_dm_post_file_open(&fs, "File") != FL_OK) return false; } strInput.MakeLower(); BOOLEAN ok = __TheSigner.Sign(strInput, strOutput); if (ok && output_name != NULL) wxStrncpy(output_name, strOutput, _MAX_PATH); return ok; } BOOLEAN xvt_sign_test(const char* input_name) { wxString strInput = input_name; if (strInput.IsEmpty()) { FILE_SPEC fs; xvt_fsys_convert_str_to_fspec(strInput, &fs); if (xvt_dm_post_file_open(&fs, "File") != FL_OK) return FALSE; } return __TheSigner.Verify(strInput); }