/****************************************************************************** ****************************************************************************** ** ** (c) Copyright 2001-2004 Roland Mainz ** ** Permission is hereby granted, free of charge, to any person obtaining a copy ** of this software and associated documentation files (the "Software"), to deal ** in the Software without restriction, including without limitation the rights ** to use, copy, modify, merge, publish, distribute, sublicense, and/or sell ** copies of the Software, and to permit persons to whom the Software is ** furnished to do so, subject to the following conditions: ** ** The above copyright notice and this permission notice shall be included in ** all copies or substantial portions of the Software. ** ** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE ** COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER ** IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN ** CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ** ** Except as contained in this notice, the names of the copyright holders shall ** not be used in advertising or otherwise to promote the sale, use or other ** dealings in this Software without prior written authorization from said ** copyright holders. ** ****************************************************************************** *****************************************************************************/ #include "xprintutil.h" #include #include #include #include #include #include #include #ifdef XPU_USE_NSPR #include "plstr.h" #undef strtok_r #define strtok_r(s1, s2, x) PL_strtok_r((s1), (s2), (x)) #endif /* XPU_USE_NSPR */ /* List of tokens which can be used to separate entries in the * $XPSERVERLIST env var */ static const char XPServerListSeparators[] = " \t\v\n\r\f"; /* conformace only; X11 API does (currrently) not make use of |const|. * If Xlib API gets fixed these macros can be turned into empty * placeholders... (|#define MAKE_STRING_WRITABLE(x)|) :-) */ #define MAKE_STRING_WRITABLE(str) (((str)?((str) = strdup(str)):0)) #define FREE_WRITABLE_STRING(str) free((void *)(str)) #define STRING_AS_WRITABLE(str) ((char *)(str)) /* Local prototypes */ static const char *XpuGetDefaultXpPrintername(void); static const char *XpuGetXpServerList( void ); static const char *XpuEnumerateXpAttributeValue( const char *value, void **vcptr ); static const char *XpuGetCurrentAttributeGroup( void **vcptr ); static void XpuDisposeEnumerateXpAttributeValue( void **vc ); static Bool XpuEnumerateMediumSourceSizes( Display *pdpy, XPContext pcontext, const char **tray_name, const char **medium_name, int *mbool, float *ma1, float *ma2, float *ma3, float *ma4, void **vcptr ); static void XpuDisposeEnumerateMediumSourceSizes( void **vc ); /* ** XprintUtil functions start with Xpu ** */ int XpuCheckExtension( Display *pdpy ) { char *display = XDisplayString(pdpy); short major = 0, minor = 0; if( XpQueryVersion(pdpy, &major, &minor) != 0 ) { XPU_DEBUG_ONLY(printf("XpuCheckExtension: XpQueryVersion '%s' %d %d\n", XPU_NULLXSTR(display), (int)major, (int)minor)); return(1); } else { XPU_DEBUG_ONLY(printf("XpuCheckExtension: XpQueryVersion '%s' returned 0(=Xprint not supported)\n", XPU_NULLXSTR(display))); } return(0); } /* Get the default printer name from the XPRINTER env var. * If XPRINTER env var is not present looks for PDPRINTER, LPDEST, and * PRINTER (in that order) * See CDE's DtPrintSetupBox(3) manual page, too... */ static const char *XpuGetDefaultXpPrintername(void) { const char *s; /* BUG/TODO: XpPrinter resource needs to be sourced, too... */ s = getenv("XPRINTER"); if( !s ) { s = getenv("PDPRINTER"); if( !s ) { s = getenv("LPDEST"); if( !s ) { s = getenv("PRINTER"); } } } return s; } static const char *XpuGetXpServerList( void ) { const char *s; /* BUG/TODO: XpServerList resource needs to be sourced first, then append * contents of XPSERVERLIST, then remove duplicates... */ s = getenv("XPSERVERLIST"); if( s == NULL ) s = ""; return(s); } Bool XpuXprintServersAvailable( void ) { const char *s; int c = 0; /* BUGs/ToDo: * - XpServerList resource needs to be sourced, too... * (see comment for |XpuGetXpServerList|, too) * - There should be some validation whether the server entries * are * a) valid (easy :) * and * b) available (hard to implement when XOpenDisplay() should be avoided) */ s = getenv("XPSERVERLIST"); /* Check if serverlist is non-empty */ if (s) { while( *s++ ) { if( !isspace(*s) ) c++; } } /* a valid server name must at least contain the ':'-seperator * and a number (e.g. ":1") */ return( c >= 2 ); } static int XpuGetPrinter2( char *printer, char *display, Display **pdpyptr, XPContext *pcontextptr ) { Display *pdpy; XPContext pcontext; XPU_DEBUG_ONLY(printf("XpuGetPrinter2: probing display '%s' for '%s'\n", XPU_NULLXSTR(display), XPU_NULLXSTR(printer))); if( (pdpy = XOpenDisplay(display)) != NULL ) { if( XpuCheckExtension(pdpy) ) { XPPrinterList list; int list_count; /* get list of available printers... */ list = XpGetPrinterList(pdpy, printer, &list_count); if( list != NULL ) XpFreePrinterList(list); /* ...and check if printer exists... */ if( (list != NULL) && (list_count > 0) ) { if( (pcontext = XpCreateContext(pdpy, printer)) != None ) { *pdpyptr = pdpy; *pcontextptr = pcontext; return(1); } XPU_DEBUG_ONLY(printf("XpuGetPrinter2: could not create print context for '%s'\n", XPU_NULLXSTR(printer))); } } else { XPU_DEBUG_ONLY(printf("display '%s' does not support the Xprint extension\n", XPU_NULLXSTR(display))); } XCloseDisplay(pdpy); return(0); } else { XPU_DEBUG_ONLY(printf("could not open display '%s'\n", XPU_NULLXSTR(display))); return(0); } } /* acceps "printer" or "printer@display" */ int XpuGetPrinter( const char *arg_printername, Display **pdpyptr, XPContext *pcontextptr ) { Display *pdpy; XPContext pcontext; char *printername; char *s; char *tok_lasts; *pdpyptr = NULL; *pcontextptr = None; XPU_DEBUG_ONLY(printf("XpuGetPrinter: looking for '%s'\n", XPU_NULLXSTR(arg_printername))); /* strtok_r will modify string - duplicate it first... */ printername = strdup(arg_printername); if( printername == NULL ) return(0); if( (s = strtok_r(printername, "@", &tok_lasts)) != NULL ) { char *name = s; char *display = strtok_r(NULL, "@", &tok_lasts); /* if we have a display - open it and grab printer */ if( display != NULL ) { if( XpuGetPrinter2(name, display, pdpyptr, pcontextptr) ) { free(printername); return(1); } } /* if we did not get a display, travel througth all displays */ else { char *sl = strdup(XpuGetXpServerList()); if( sl != NULL ) { for( display = strtok_r(sl, XPServerListSeparators, &tok_lasts) ; display != NULL ; display = strtok_r(NULL, XPServerListSeparators, &tok_lasts) ) { if( XpuGetPrinter2(name, display, pdpyptr, pcontextptr) ) { free(sl); free(printername); return(1); } } free(sl); } } } free(printername); XPU_DEBUG_ONLY(printf("XpuGetPrinter: failure\n")); return(0); } void XpuClosePrinterDisplay(Display *pdpy, XPContext pcontext) { if( pdpy ) { if( pcontext != None ) XpDestroyContext(pdpy, pcontext); XCloseDisplay(pdpy); } } void XpuSetOneAttribute( Display *pdpy, XPContext pcontext, XPAttributes type, const char *attribute_name, const char *value, XPAttrReplacement replacement_rule ) { /* Alloc buffer for sprintf() stuff below */ char *buffer = (char *)malloc(strlen(attribute_name)+strlen(value)+4); if( buffer != NULL ) { sprintf(buffer, "%s: %s", attribute_name, value); XpSetAttributes(pdpy, pcontext, type, buffer, replacement_rule); free(buffer); } } void XpuSetOneLongAttribute( Display *pdpy, XPContext pcontext, XPAttributes type, const char *attribute_name, long value, XPAttrReplacement replacement_rule ) { /* Alloc buffer for sprintf() stuff below */ char *buffer = (char *)malloc(strlen(attribute_name)+32+4); if( buffer != NULL ) { sprintf(buffer, "%s: %ld", attribute_name, value); XpSetAttributes(pdpy, pcontext, type, buffer, replacement_rule); free(buffer); } } /* Check if attribute value is supported or not * Use this function _only_ if XpuGetSupported{Job,Doc,Page}Attributes() * does not help you... */ int XpuCheckSupported( Display *pdpy, XPContext pcontext, XPAttributes type, const char *attribute_name, const char *query ) { char *value; void *tok_lasts; MAKE_STRING_WRITABLE(attribute_name); if( attribute_name == NULL ) return(0); value = XpGetOneAttribute(pdpy, pcontext, type, STRING_AS_WRITABLE(attribute_name)); XPU_DEBUG_ONLY(printf("XpuCheckSupported: XpGetOneAttribute(%s) returned '%s'\n", XPU_NULLXSTR(attribute_name), XPU_NULLXSTR(value))); FREE_WRITABLE_STRING(attribute_name); if( value != NULL ) { const char *s; for( s = XpuEnumerateXpAttributeValue(value, &tok_lasts) ; s != NULL ; s = XpuEnumerateXpAttributeValue(NULL, &tok_lasts) ) { XPU_DEBUG_ONLY(printf("XpuCheckSupported: probing '%s'=='%s'\n", XPU_NULLXSTR(s), XPU_NULLXSTR(query))); if( !strcmp(s, query) ) { XFree(value); XpuDisposeEnumerateXpAttributeValue(&tok_lasts); return(1); } } XpuDisposeEnumerateXpAttributeValue(&tok_lasts); XFree(value); } return(0); } int XpuSetJobTitle( Display *pdpy, XPContext pcontext, const char *title ) { if( XpuGetSupportedJobAttributes(pdpy, pcontext) & XPUATTRIBUTESUPPORTED_JOB_NAME ) { char *encoded_title; encoded_title = XpuResourceEncode(title); if (!encoded_title) return(0); XpuSetOneAttribute(pdpy, pcontext, XPJobAttr, "*job-name", encoded_title, XPAttrMerge); XpuResourceFreeString(encoded_title); return(1); } else { XPU_DEBUG_ONLY(printf("XpuSetJobTitle: XPUATTRIBUTESUPPORTED_JOB_NAME not supported ('%s')\n", XPU_NULLXSTR(title))); return(0); } } int XpuGetOneLongAttribute( Display *pdpy, XPContext pcontext, XPAttributes type, const char *attribute_name, long *result ) { char *s; MAKE_STRING_WRITABLE(attribute_name); if( attribute_name == NULL ) return(0); s = XpGetOneAttribute(pdpy, pcontext, type, STRING_AS_WRITABLE(attribute_name)); if(s && *s) { long tmp; XPU_DEBUG_ONLY(printf("XpuGetOneLongAttribute: '%s' got '%s'\n", XPU_NULLXSTR(attribute_name), XPU_NULLXSTR(s))); tmp = strtol(s, (char **)NULL, 10); if( !(((tmp == 0L) || (tmp == LONG_MIN) || (tmp == LONG_MAX)) && ((errno == ERANGE) || (errno == EINVAL))) ) { *result = tmp; XFree(s); XPU_DEBUG_ONLY(printf("XpuGetOneLongAttribute: result %ld\n", *result)); FREE_WRITABLE_STRING(attribute_name); return(1); } } if( s != NULL ) XFree(s); FREE_WRITABLE_STRING(attribute_name); return(0); } #ifdef DEBUG /* debug only */ void dumpXpAttributes( Display *pdpy, XPContext pcontext ) { char *s; printf("------------------------------------------------\n"); printf("--> Job\n%s\n", s=XpuGetJobAttributes(pdpy, pcontext)); XFree(s); printf("--> Doc\n%s\n", s=XpuGetDocAttributes(pdpy, pcontext)); XFree(s); printf("--> Page\n%s\n", s=XpuGetPageAttributes(pdpy, pcontext)); XFree(s); printf("--> Printer\n%s\n", s=XpuGetPrinterAttributes(pdpy, pcontext)); XFree(s); printf("--> Server\n%s\n", s=XpuGetServerAttributes(pdpy, pcontext)); XFree(s); printf("image resolution %d\n", (int)XpGetImageResolution(pdpy, pcontext)); printf("------------------------------------------------\n"); } #endif /* DEBUG */ typedef struct XpuIsNotifyEventContext_ { int event_base; int detail; } XpuIsNotifyEventContext; static Bool IsXpNotifyEvent( Display *pdpy, XEvent *ev, XPointer arg ) { Bool match; XpuIsNotifyEventContext *context = (XpuIsNotifyEventContext *)arg; XPPrintEvent *pev = (XPPrintEvent *)ev; match = pev->type == (context->event_base+XPPrintNotify) && pev->detail == context->detail; XPU_DEBUG_ONLY(printf("XpuWaitForPrintNotify: %d=IsXpNotifyEvent(%d,%d)\n", (int)match, (int)pev->type, (int)pev->detail)); return match; } void XpuWaitForPrintNotify( Display *pdpy, int xp_event_base, int detail ) { XEvent dummy; XpuIsNotifyEventContext matchcontext; matchcontext.event_base = xp_event_base; matchcontext.detail = detail; XIfEvent(pdpy, &dummy, IsXpNotifyEvent, (XPointer)&matchcontext); } static const char *skip_matching_brackets(const char *start) { const char *s = start; int level = 0; if( !start ) return(NULL); do { switch(*s++) { case '\0': return(NULL); case '{': level++; break; case '}': level--; break; } } while(level > 0); return(s); } static const char *search_next_space(const char *start) { const char *s = start; int level = 0; if( !start ) return(NULL); for(;;) { if( isspace(*s) ) return(s); if( *s=='\0' ) return(NULL); s++; } } /* PRIVATE context data for XpuEnumerateXpAttributeValue() */ typedef struct _XpuAttributeValueEnumeration { char *value; size_t original_value_len; /* original length of value */ char *group; char *start; char *s; } XpuAttributeValueEnumeration; /* Hacked parser for Xp values and enumerations */ static const char *XpuEnumerateXpAttributeValue( const char *value, void **vcptr ) { XpuAttributeValueEnumeration **cptr = (XpuAttributeValueEnumeration **)vcptr; XpuAttributeValueEnumeration *context; const char *tmp; if( !cptr ) return(NULL); if( value ) { XpuAttributeValueEnumeration *e; const char *s = value; Bool isGroup = FALSE; e = (XpuAttributeValueEnumeration *)malloc(sizeof(XpuAttributeValueEnumeration)); if( !e ) return NULL; /* Skip leading '{'. */ while(*s=='{' && isGroup==FALSE) { s++; isGroup = TRUE; } /* Skip leading blanks. */ while(isspace(*s)) s++; e->group = NULL; /* Read group name. */ if( isGroup ) { tmp = s; while(!isspace(*s)) s++; if(strncmp(tmp, "''", s-tmp) != 0) { e->group = strdup(tmp); e->group[s-tmp] = '\0'; } } e->original_value_len = strlen(s); e->value = (char *)malloc(e->original_value_len+4); /* We may look up to three bytes beyond the string */ strcpy(e->value, s); memset(e->value+e->original_value_len+1, 0, 3); /* quad termination */ e->start = e->s = e->value; *cptr = e; } context = *cptr; if( !context || !context->s ) return(NULL); /* Skip leading blanks, '\'' or '}' */ while(isspace(*(context->s)) || *(context->s)=='\'' /*|| *(context->s)=='}'*/ ) context->s++; if( *(context->s) == '\0' ) return(NULL); context->start = context->s; if( *(context->start) == '{' ) context->s = (char *)skip_matching_brackets(context->start); else context->s = (char *)search_next_space(context->start); /* end of string reached ? */ if( context->s ) { *(context->s) = '\0'; context->s++; } /* Check if we reached a new attribute group */ tmp = context->start; while(isspace(*tmp)) tmp++; if( *tmp=='}' ) { void *prev_cptr = *vcptr; tmp+=2; /* We have 3*'\0' at the end of the string - this is legal! */ if( *tmp!='\0' ) { const char *ret; /* Start the parser again */ *vcptr = NULL; ret = XpuEnumerateXpAttributeValue(tmp, vcptr); /* Free old context */ XpuDisposeEnumerateXpAttributeValue(&prev_cptr); return(ret); } else { return(NULL); } } return(context->start); } /* Get enumeration group for last string returned by |XpuEnumerateXpAttributeValue|... */ static const char *XpuGetCurrentAttributeGroup( void **vcptr ) { XpuAttributeValueEnumeration **cptr = (XpuAttributeValueEnumeration **)vcptr; if( !cptr ) return(NULL); if( !*cptr ) return(NULL); return((*cptr)->group); } static void XpuDisposeEnumerateXpAttributeValue( void **vc ) { if( vc ) { XpuAttributeValueEnumeration *context = *((XpuAttributeValueEnumeration **)vc); free(context->value); if(context->group) free(context->group); free(context); } } /* parse a paper size string * (example: '{na-letter False {6.3500 209.5500 6.3500 273.0500}}') */ static Bool XpuParseMediumSourceSize( const char *value, const char **medium_name, int *mbool, float *ma1, float *ma2, float *ma3, float *ma4 ) { const char *s; char *d, *name; char *boolbuf; size_t value_len; int num_input_items; const char *cur_locale; if( value && value[0]!='{' && value[0]!='\0' ) return(False); value_len = strlen(value); /* alloc buffer for |medium_name| and |boolbuf| in one step * (both must be large enougth to hold at least |strlen(value)+1| bytes) */ name = (char *)malloc(value_len*2 + 4); boolbuf = name + value_len+2; /* |boolbuf| starts directly after |name| */ /* remove '{' && '}' */ s = value; d = name; do { *d = tolower(*s); if( *s!='{' && *s!='}' ) d++; s++; } while(*s); *d = '\0'; /* separate medium name from string */ d = (char *)search_next_space(name); if( !d ) { free(name); return(False); } *d = '\0'; *medium_name = name; /* ... continue to parse the remaining string... */ d++; /* Force C/POSIX radix for scanf()-parsing (see bug 131831 ("Printing * does not work in de_AT@euro locale")), do the parsing and restore * the original locale. * XXX: This may affect all threads and not only the calling one... */ { #define CUR_LOCALE_SIZE 256 char cur_locale[CUR_LOCALE_SIZE+1]; strncpy(cur_locale, setlocale(LC_NUMERIC, NULL), CUR_LOCALE_SIZE); cur_locale[CUR_LOCALE_SIZE]='\0'; setlocale(LC_NUMERIC, "C"); num_input_items = sscanf(d, "%s %f %f %f %f", boolbuf, ma1, ma2, ma3, ma4); setlocale(LC_NUMERIC, cur_locale); #undef CUR_LOCALE_SIZE } if( num_input_items != 5 ) { free(name); return(False); } if( !strcmp(boolbuf, "true") ) *mbool = True; else if( !strcmp(boolbuf, "false") ) *mbool = False; else { free(name); return(False); } return(True); } /* parse a paper size string * (example: '{na-letter False {6.3500 209.5500 6.3500 273.0500}}') */ static Bool XpuEnumerateMediumSourceSizes( Display *pdpy, XPContext pcontext, const char **tray_name, const char **medium_name, int *mbool, float *ma1, float *ma2, float *ma3, float *ma4, void **vcptr ) { const char *medium_spec; const char *value = NULL; if( pdpy && pcontext ) { value = XpGetOneAttribute(pdpy, pcontext, XPPrinterAttr, "medium-source-sizes-supported"); if( !value ) return(False); } while(1) { medium_spec = XpuEnumerateXpAttributeValue(value, vcptr); if( value ) { XFree((void *)value); value = NULL; } /* enumeration done? */ if( !medium_spec ) return(False); if (XpuParseMediumSourceSize(medium_spec, medium_name, mbool, ma1, ma2, ma3, ma4)) { *tray_name = XpuGetCurrentAttributeGroup(vcptr); return(True); } else { /* Should never ever happen! */ fprintf(stderr, "XpuEnumerateMediumSourceSize: error parsing '%s'\n", medium_spec); } } /* not reached */ } static void XpuDisposeEnumerateMediumSourceSizes( void **vc ) { XpuDisposeEnumerateXpAttributeValue(vc); } /* future: Migrate this functionality into |XpGetPrinterList| - just do * not pass a |Display *| to |XpGetPrinterList| */ XPPrinterList XpuGetPrinterList( const char *printer, int *res_list_count ) { XPPrinterRec *rec = NULL; int rec_count = 1; /* Allocate one more |XPPrinterRec| structure * as terminator */ char *sl; const char *default_printer_name = XpuGetDefaultXpPrintername(); int default_printer_rec_index = -1; if( !res_list_count ) return(NULL); sl = strdup(XpuGetXpServerList()); MAKE_STRING_WRITABLE(printer); if( sl != NULL ) { char *display; char *tok_lasts; for( display = strtok_r(sl, XPServerListSeparators, &tok_lasts) ; display != NULL ; display = strtok_r(NULL, XPServerListSeparators, &tok_lasts) ) { Display *pdpy; if( (pdpy = XOpenDisplay(display)) != NULL ) { XPPrinterList list; int list_count; size_t display_len = strlen(display); /* get list of available printers... */ list = XpGetPrinterList(pdpy, STRING_AS_WRITABLE(printer), &list_count); if( list && list_count ) { int i; for( i = 0 ; i < list_count ; i++ ) { char *s; /* Workaround for http://bugzilla.mozilla.org/show_bug.cgi?id=193499 * ("Xprint print/print preview crashes Mozilla") where the Solaris * Xprt may create invalid entries (e.g. |XpGetPrinterList| will * return |list[i].name==NULL| due to empty lines in the printer list. */ if( !list[i].name ) continue; rec_count++; rec = (XPPrinterRec *)realloc(rec, sizeof(XPPrinterRec)*rec_count); if( !rec ) /* failure */ break; s = (char *)malloc(strlen(list[i].name)+display_len+4); sprintf(s, "%s@%s", list[i].name, display); rec[rec_count-2].name = s; rec[rec_count-2].desc = (list[i].desc)?(strdup(list[i].desc)):(NULL); /* Test for default printer (if the user set one).*/ if( default_printer_name ) { /* Default_printer_name may either contain the FQPN(=full * qualified printer name ("foo@myhost:5") or just the name * ("foo")) */ if( (!strcmp(list[i].name, default_printer_name)) || (!strcmp(s, default_printer_name)) ) { /* Remember index of default printer that we can swap it to * the head of the array below... */ default_printer_rec_index = rec_count-2; } } } XpFreePrinterList(list); } XCloseDisplay(pdpy); } } free(sl); } if( rec ) { /* users: DO NOT COUNT ON THIS DETAIL * (this is only to make current impl. of XpuFreePrinterList() easier) * I may remove this implementation detail in a later revision of * the library! */ rec[rec_count-1].name = NULL; rec[rec_count-1].desc = NULL; rec_count--; } else { rec_count = 0; } /* The default printer is always the first one in the printer list... */ if( (default_printer_rec_index != -1) && rec ) { XPPrinterRec tmp; tmp = rec[0]; rec[0] = rec[default_printer_rec_index]; rec[default_printer_rec_index] = tmp; } *res_list_count = rec_count; FREE_WRITABLE_STRING(printer); return(rec); } void XpuFreePrinterList( XPPrinterList list ) { if( list ) { XPPrinterRec *curr = list; /* See the warning abouve about using this implementation detail for * checking for the list's end... */ while( curr->name != NULL ) { free(curr->name); if(curr->desc) free(curr->desc); curr++; } free(list); } } /* Set number of copies to print from this document */ int XpuSetDocumentCopies( Display *pdpy, XPContext pcontext, long num_copies ) { if( XpuGetSupportedDocAttributes(pdpy, pcontext) & XPUATTRIBUTESUPPORTED_COPY_COUNT) { XpuSetOneLongAttribute(pdpy, pcontext, XPDocAttr, "*copy-count", num_copies, XPAttrMerge); return(1); } else { XPU_DEBUG_ONLY(printf("XpuSetContentOrientation: XPUATTRIBUTESUPPORTED_COPY_COUNT not supported\n")); /* Failure... */ return(0); } } XpuMediumSourceSizeList XpuGetMediumSourceSizeList( Display *pdpy, XPContext pcontext, int *numEntriesPtr ) { XpuMediumSourceSizeList list = NULL; int rec_count = 1; /* allocate one more |XpuMediumSourceSizeRec| structure * as terminator */ Bool status; float ma1, ma2, ma3, ma4; char *value; void *tok_lasts; const char *tray_name, *medium_name; int mbool; const char *default_tray, *default_medium; int default_medium_rec_index = -1; default_tray = XpGetOneAttribute(pdpy, pcontext, XPDocAttr, "default-input-tray"); if(!default_tray) { fprintf(stderr, "XpuGetMediumSourceSizeList: Internal error, no 'default-input-tray' found.\n"); return(NULL); } default_medium = XpGetOneAttribute(pdpy, pcontext, XPDocAttr, "default-medium"); if(!default_medium) { fprintf(stderr, "XpuGetMediumSourceSizeList: Internal error, no 'default-medium' found.\n"); XFree((void *)default_tray); return(NULL); } for( status = XpuEnumerateMediumSourceSizes(pdpy, pcontext, &tray_name, &medium_name, &mbool, &ma1, &ma2, &ma3, &ma4, &tok_lasts) ; status != False ; status = XpuEnumerateMediumSourceSizes(NULL, None, &tray_name, &medium_name, &mbool, &ma1, &ma2, &ma3, &ma4, &tok_lasts) ) { rec_count++; list = (XpuMediumSourceSizeRec *)realloc(list, sizeof(XpuMediumSourceSizeRec)*rec_count); if( !list ) return(NULL); list[rec_count-2].tray_name = (tray_name)?(strdup(tray_name)):(NULL); list[rec_count-2].medium_name = strdup(medium_name); list[rec_count-2].mbool = mbool; list[rec_count-2].ma1 = ma1; list[rec_count-2].ma2 = ma2; list[rec_count-2].ma3 = ma3; list[rec_count-2].ma4 = ma4; /* Default medium ? */ if( (!strcmp(medium_name, default_medium)) && ((tray_name && (*default_tray))?(!strcmp(tray_name, default_tray)):(True)) ) { default_medium_rec_index = rec_count-2; } } XpuDisposeEnumerateMediumSourceSizes(&tok_lasts); if( list ) { /* users: DO NOT COUNT ON THIS DETAIL * (this is only to make current impl. of XpuFreeMediumSourceSizeList() easier) * I may remove this implementation detail in a later revision of * the library! */ list[rec_count-1].tray_name = NULL; list[rec_count-1].medium_name = NULL; rec_count--; } else { rec_count = 0; } /* Make the default medium always the first item in the list... */ if( (default_medium_rec_index != -1) && list ) { XpuMediumSourceSizeRec tmp; tmp = list[0]; list[0] = list[default_medium_rec_index]; list[default_medium_rec_index] = tmp; } *numEntriesPtr = rec_count; return(list); } void XpuFreeMediumSourceSizeList( XpuMediumSourceSizeList list ) { if( list ) { XpuMediumSourceSizeRec *curr = list; /* See the warning abouve about using this implementation detail for * checking for the list's end... */ while( curr->medium_name != NULL ) { if( curr->tray_name) free((void *)curr->tray_name); free((void *)curr->medium_name); curr++; } free(list); } } static int XpuSetMediumSourceSize( Display *pdpy, XPContext pcontext, XPAttributes type, XpuMediumSourceSizeRec *medium_spec ) { /* Set the "default-medium" and "*default-input-tray" * (if |XpuEnumerateMediumSourceSizes| returned one) XPDocAttr's * attribute and return */ if (medium_spec->tray_name) { XpuSetOneAttribute(pdpy, pcontext, type, "*default-input-tray", medium_spec->tray_name, XPAttrMerge); } XpuSetOneAttribute(pdpy, pcontext, type, "*default-medium", medium_spec->medium_name, XPAttrMerge); return( 1 ); } /* Set document medium size */ int XpuSetDocMediumSourceSize( Display *pdpy, XPContext pcontext, XpuMediumSourceSizeRec *medium_spec ) { XpuSupportedFlags doc_supported_flags; doc_supported_flags = XpuGetSupportedDocAttributes(pdpy, pcontext); if( (doc_supported_flags & XPUATTRIBUTESUPPORTED_DEFAULT_MEDIUM) == 0 ) return( 0 ); if (medium_spec->tray_name) { if( (doc_supported_flags & XPUATTRIBUTESUPPORTED_DEFAULT_INPUT_TRAY) == 0 ) return( 0 ); } return XpuSetMediumSourceSize(pdpy, pcontext, XPDocAttr, medium_spec); } /* Set page medium size */ int XpuSetPageMediumSourceSize( Display *pdpy, XPContext pcontext, XpuMediumSourceSizeRec *medium_spec ) { XpuSupportedFlags page_supported_flags; page_supported_flags = XpuGetSupportedPageAttributes(pdpy, pcontext); if( (page_supported_flags & XPUATTRIBUTESUPPORTED_DEFAULT_MEDIUM) == 0 ) return( 0 ); if (medium_spec->tray_name) { if( (page_supported_flags & XPUATTRIBUTESUPPORTED_DEFAULT_INPUT_TRAY) == 0 ) return( 0 ); } return XpuSetMediumSourceSize(pdpy, pcontext, XPPageAttr, medium_spec); } #ifndef ABS #define ABS(x) ((x)<0?-(x):(x)) #endif /* ABS */ #define MORE_OR_LESS_EQUAL(a, b, tolerance) (ABS((a) - (b)) <= (tolerance)) XpuMediumSourceSizeRec * XpuFindMediumSourceSizeBySize( XpuMediumSourceSizeList mlist, int mlist_count, float page_width_mm, float page_height_mm, float tolerance ) { int i; for( i = 0 ; i < mlist_count ; i++ ) { XpuMediumSourceSizeRec *curr = &mlist[i]; float total_width = curr->ma1 + curr->ma2, total_height = curr->ma3 + curr->ma4; /* Match width/height*/ if( ((page_width_mm !=-1.f)?(MORE_OR_LESS_EQUAL(total_width, page_width_mm, tolerance)):(True)) && ((page_height_mm!=-1.f)?(MORE_OR_LESS_EQUAL(total_height, page_height_mm, tolerance)):(True)) ) { return(curr); } } return(NULL); } XpuMediumSourceSizeRec * XpuFindMediumSourceSizeByBounds( XpuMediumSourceSizeList mlist, int mlist_count, float m1, float m2, float m3, float m4, float tolerance ) { int i; for( i = 0 ; i < mlist_count ; i++ ) { XpuMediumSourceSizeRec *curr = &mlist[i]; /* Match bounds */ if( ((m1!=-1.f)?(MORE_OR_LESS_EQUAL(curr->ma1, m1, tolerance)):(True)) && ((m2!=-1.f)?(MORE_OR_LESS_EQUAL(curr->ma2, m2, tolerance)):(True)) && ((m3!=-1.f)?(MORE_OR_LESS_EQUAL(curr->ma3, m3, tolerance)):(True)) && ((m4!=-1.f)?(MORE_OR_LESS_EQUAL(curr->ma4, m4, tolerance)):(True)) ) { return(curr); } } return(NULL); } XpuMediumSourceSizeRec * XpuFindMediumSourceSizeByName( XpuMediumSourceSizeList mlist, int mlist_count, const char *tray_name, const char *medium_name ) { int i; for( i = 0 ; i < mlist_count ; i++ ) { XpuMediumSourceSizeRec *curr = &mlist[i]; /* Match by tray name and/or medium name */ if( ((tray_name && curr->tray_name)?(!strcasecmp(curr->tray_name, tray_name)):(tray_name==NULL)) && ((medium_name)?(!strcasecmp(curr->medium_name, medium_name)):(True)) ) { return(curr); } } return(NULL); } XpuResolutionList XpuGetResolutionList( Display *pdpy, XPContext pcontext, int *numEntriesPtr ) { XpuResolutionList list = NULL; int rec_count = 1; /* Allocate one more |XpuResolutionRec| structure * as terminator */ char *value; char *tok_lasts; const char *s; long default_resolution = -1; int default_resolution_rec_index = -1; char namebuf[64]; /* Get default document resolution */ if( XpuGetOneLongAttribute(pdpy, pcontext, XPDocAttr, "default-printer-resolution", &default_resolution) != 1 ) { default_resolution = -1; } value = XpGetOneAttribute(pdpy, pcontext, XPPrinterAttr, "printer-resolutions-supported"); if (!value) { fprintf(stderr, "XpuGetResolutionList: Internal error, no 'printer-resolutions-supported' XPPrinterAttr found.\n"); return(NULL); } for( s = strtok_r(value, " ", &tok_lasts) ; s != NULL ; s = strtok_r(NULL, " ", &tok_lasts) ) { long tmp; tmp = strtol(s, (char **)NULL, 10); if( ((tmp == 0L) || (tmp == LONG_MIN) || (tmp == LONG_MAX)) && ((errno == ERANGE) || (errno == EINVAL)) ) { fprintf(stderr, "XpuGetResolutionList: Internal parser errror for '%s'.\n", s); continue; } rec_count++; list = (XpuResolutionRec *)realloc(list, sizeof(XpuResolutionRec)*rec_count); if( !list ) return(NULL); sprintf(namebuf, "%lddpi", tmp); list[rec_count-2].name = strdup(namebuf); list[rec_count-2].x_dpi = tmp; list[rec_count-2].y_dpi = tmp; if( default_resolution != -1 ) { /* Is this the default resolution ? */ if( (list[rec_count-2].x_dpi == default_resolution) && (list[rec_count-2].y_dpi == default_resolution) ) { default_resolution_rec_index = rec_count-2; } } } XFree(value); if( list ) { /* users: DO NOT COUNT ON THIS DETAIL * (this is only to make current impl. of XpuGetResolutionList() easier) * We may remove this implementation detail in a later revision of * the library! */ list[rec_count-1].name = NULL; list[rec_count-1].x_dpi = -1; list[rec_count-1].y_dpi = -1; rec_count--; } else { rec_count = 0; } /* Make the default resolution always the first item in the list... */ if( (default_resolution_rec_index != -1) && list ) { XpuResolutionRec tmp; tmp = list[0]; list[0] = list[default_resolution_rec_index]; list[default_resolution_rec_index] = tmp; } *numEntriesPtr = rec_count; return(list); } void XpuFreeResolutionList( XpuResolutionList list ) { if( list ) { XpuResolutionRec *curr = list; /* See the warning abouve about using this implementation detail for * checking for the list's end... */ while( curr->name != NULL ) { free((void *)curr->name); curr++; } free(list); } } /* Find resolution in resolution list. */ XpuResolutionRec *XpuFindResolutionByName( XpuResolutionList list, int list_count, const char *name) { int i; for( i = 0 ; i < list_count ; i++ ) { XpuResolutionRec *curr = &list[i]; if (!strcasecmp(curr->name, name)) return curr; /* Search by plain DPI value (no "dpi" suffix )*/ if (curr->x_dpi == curr->x_dpi) { char buf[32]; sprintf(buf, "%ld", curr->x_dpi); if (!strcasecmp(buf, name)) return curr; } } return NULL; } /* Get default page (if defined) or document resolution * this function may fail in the following conditions: * - No default resolution set yet * - X DPI != Y DPI (not yet implemented in Xprt) */ Bool XpuGetResolution( Display *pdpy, XPContext pcontext, long *x_dpi_ptr, long *y_dpi_ptr ) { long dpi; /* Try to get the current page's resolution (pages may differ in resolution if the DDX supports this) */ if( XpuGetOneLongAttribute(pdpy, pcontext, XPPageAttr, "default-printer-resolution", &dpi) == 1 ) { *x_dpi_ptr = dpi; *y_dpi_ptr = dpi; return True; } /* Get document resolution */ if( XpuGetOneLongAttribute(pdpy, pcontext, XPDocAttr, "default-printer-resolution", &dpi) == 1 ) { *x_dpi_ptr = dpi; *y_dpi_ptr = dpi; return True; } return False; } static int XpuSetResolution( Display *pdpy, XPContext pcontext, XPAttributes type, XpuResolutionRec *rec ) { if( rec->x_dpi != rec->y_dpi ) { fprintf(stderr, "XpuSetResolution: internal error: x_dpi != y_dpi not supported yet.\n"); return 0; } XpuSetOneLongAttribute(pdpy, pcontext, type, "*default-printer-resolution", rec->x_dpi, XPAttrMerge); return( 1 ); } /* Set document resolution * Retun error if printer does not support setting a resolution */ int XpuSetDocResolution( Display *pdpy, XPContext pcontext, XpuResolutionRec *rec ) { if( (XpuGetSupportedDocAttributes(pdpy, pcontext) & XPUATTRIBUTESUPPORTED_DEFAULT_PRINTER_RESOLUTION) == 0 ) return( 0 ); return XpuSetResolution(pdpy, pcontext, XPDocAttr, rec); } /* Set page medium size * Retun error if printer does not support setting a resolution or if per-page * resolution changes are not allowed. */ int XpuSetPageResolution( Display *pdpy, XPContext pcontext, XpuResolutionRec *rec ) { if( (XpuGetSupportedPageAttributes(pdpy, pcontext) & XPUATTRIBUTESUPPORTED_DEFAULT_PRINTER_RESOLUTION) == 0 ) return( 0 ); return XpuSetResolution(pdpy, pcontext, XPPageAttr, rec); } XpuOrientationList XpuGetOrientationList( Display *pdpy, XPContext pcontext, int *numEntriesPtr ) { XpuOrientationList list = NULL; int rec_count = 1; /* Allocate one more |XpuOrientationRec| * structure as terminator */ char *value; char *tok_lasts; const char *s; const char *default_orientation = NULL; int default_orientation_rec_index = -1; /* Get default document orientation */ default_orientation = XpGetOneAttribute(pdpy, pcontext, XPDocAttr, "content-orientation"); if( !default_orientation ) { fprintf(stderr, "XpuGetOrientationList: Internal error, no 'content-orientation' XPDocAttr found.\n"); return(NULL); } value = XpGetOneAttribute(pdpy, pcontext, XPPrinterAttr, "content-orientations-supported"); if (!value) { fprintf(stderr, "XpuGetOrientationList: Internal error, no 'content-orientations-supported' XPPrinterAttr found.\n"); return(NULL); } for( s = strtok_r(value, " ", &tok_lasts) ; s != NULL ; s = strtok_r(NULL, " ", &tok_lasts) ) { rec_count++; list = (XpuOrientationRec *)realloc(list, sizeof(XpuOrientationRec)*rec_count); if( !list ) return(NULL); list[rec_count-2].orientation = strdup(s); /* Default resolution ? */ if( !strcmp(list[rec_count-2].orientation, default_orientation) ) { default_orientation_rec_index = rec_count-2; } } XFree(value); XFree((void *)default_orientation); if( list ) { /* users: DO NOT COUNT ON THIS DETAIL * (this is only to make current impl. of XpuFreeOrientationList() easier) * I may remove this implementation detail in a later revision of * the library! */ list[rec_count-1].orientation = NULL; rec_count--; } else { rec_count = 0; } /* Make the default orientation always the first item in the list... */ if( (default_orientation_rec_index != -1) && list ) { XpuOrientationRec tmp; tmp = list[0]; list[0] = list[default_orientation_rec_index]; list[default_orientation_rec_index] = tmp; } *numEntriesPtr = rec_count; return(list); } void XpuFreeOrientationList( XpuOrientationList list ) { if( list ) { XpuOrientationRec *curr = list; /* See the warning abouve about using this implementation detail for * checking for the list's end... */ while( curr->orientation != NULL ) { free((void *)curr->orientation); curr++; } free(list); } } XpuOrientationRec * XpuFindOrientationByName( XpuOrientationList list, int list_count, const char *orientation ) { int i; for( i = 0 ; i < list_count ; i++ ) { XpuOrientationRec *curr = &list[i]; if (!strcasecmp(curr->orientation, orientation)) return curr; } return(NULL); } static int XpuSetOrientation( Display *pdpy, XPContext pcontext, XPAttributes type, XpuOrientationRec *rec ) { XpuSetOneAttribute(pdpy, pcontext, type, "*content-orientation", rec->orientation, XPAttrMerge); return(1); } /* Set document orientation * Retun error if printer does not support setting an orientation */ int XpuSetDocOrientation( Display *pdpy, XPContext pcontext, XpuOrientationRec *rec ) { if( (XpuGetSupportedDocAttributes(pdpy, pcontext) & XPUATTRIBUTESUPPORTED_CONTENT_ORIENTATION) == 0 ) return( 0 ); return XpuSetOrientation(pdpy, pcontext, XPDocAttr, rec); } /* Set page orientation * Retun error if printer does not support setting an orientation or if * per-page orientations changes are not allowed */ int XpuSetPageOrientation( Display *pdpy, XPContext pcontext, XpuOrientationRec *rec ) { if( (XpuGetSupportedPageAttributes(pdpy, pcontext) & XPUATTRIBUTESUPPORTED_CONTENT_ORIENTATION) == 0 ) return( 0 ); return XpuSetOrientation(pdpy, pcontext, XPPageAttr, rec); } XpuPlexList XpuGetPlexList( Display *pdpy, XPContext pcontext, int *numEntriesPtr ) { XpuPlexList list = NULL; int rec_count = 1; /* Allocate one more |XpuPlexList| structure * as terminator */ char *value; char *tok_lasts; const char *s; const char *default_plex = NULL; int default_plex_rec_index = -1; /* Get default document plex */ default_plex = XpGetOneAttribute(pdpy, pcontext, XPDocAttr, "plex"); if( !default_plex ) { fprintf(stderr, "XpuGetPlexList: Internal error, no 'plex' XPDocAttr found.\n"); return(NULL); } value = XpGetOneAttribute(pdpy, pcontext, XPPrinterAttr, "plexes-supported"); if (!value) { fprintf(stderr, "XpuGetPlexList: Internal error, no 'plexes-supported' XPPrinterAttr found.\n"); return(NULL); } for( s = strtok_r(value, " ", &tok_lasts) ; s != NULL ; s = strtok_r(NULL, " ", &tok_lasts) ) { rec_count++; list = (XpuPlexRec *)realloc(list, sizeof(XpuPlexRec)*rec_count); if( !list ) return(NULL); list[rec_count-2].plex = strdup(s); /* Default plex ? */ if( !strcmp(list[rec_count-2].plex, default_plex) ) { default_plex_rec_index = rec_count-2; } } XFree(value); XFree((void *)default_plex); if( list ) { /* users: DO NOT COUNT ON THIS DETAIL * (this is only to make current impl. of XpuFreePlexList() easier) * I may remove this implementation detail in a later revision of * the library! */ list[rec_count-1].plex = NULL; rec_count--; } else { rec_count = 0; } /* Make the default plex always the first item in the list... */ if( (default_plex_rec_index != -1) && list ) { XpuPlexRec tmp; tmp = list[0]; list[0] = list[default_plex_rec_index]; list[default_plex_rec_index] = tmp; } *numEntriesPtr = rec_count; return(list); } void XpuFreePlexList( XpuPlexList list ) { if( list ) { XpuPlexRec *curr = list; /* See the warning abouve about using this implementation detail for * checking for the list's end... */ while( curr->plex != NULL ) { free((void *)curr->plex); curr++; } free(list); } } XpuPlexRec * XpuFindPlexByName( XpuPlexList list, int list_count, const char *plex ) { int i; for( i = 0 ; i < list_count ; i++ ) { XpuPlexRec *curr = &list[i]; if (!strcasecmp(curr->plex, plex)) return curr; } return(NULL); } static int XpuSetContentPlex( Display *pdpy, XPContext pcontext, XPAttributes type, XpuPlexRec *rec ) { XpuSetOneAttribute(pdpy, pcontext, type, "*plex", rec->plex, XPAttrMerge); return(1); } /* Set document plex * Retun error if printer does not support setting an plex */ int XpuSetDocPlex( Display *pdpy, XPContext pcontext, XpuPlexRec *rec ) { if( (XpuGetSupportedDocAttributes(pdpy, pcontext) & XPUATTRIBUTESUPPORTED_PLEX) == 0 ) return( 0 ); return XpuSetContentPlex(pdpy, pcontext, XPDocAttr, rec); } /* Set page plex * Retun error if printer does not support setting an plex or if * per-page plex changes are not allowed */ int XpuSetPagePlex( Display *pdpy, XPContext pcontext, XpuPlexRec *rec ) { if( (XpuGetSupportedPageAttributes(pdpy, pcontext) & XPUATTRIBUTESUPPORTED_PLEX) == 0 ) return( 0 ); return XpuSetContentPlex(pdpy, pcontext, XPPageAttr, rec); } XpuColorspaceList XpuGetColorspaceList( Display *pdpy, XPContext pcontext, int *numEntriesPtr ) { XpuColorspaceList list = NULL; int rec_count = 1; /* Allocate one more |XpuColorspaceRec| structure * as terminator */ char namebuf[256]; /* Temporary name buffer for colorspace names */ int i; /* Loop counter */ int nvi; /* Number of visuals */ Screen *pscreen; /* Print screen */ XVisualInfo viproto; /* fill in for getting info */ XVisualInfo *vip; /* retured info */ pscreen = XpGetScreenOfContext(pdpy, pcontext); nvi = 0; viproto.screen = XScreenNumberOfScreen(pscreen); vip = XGetVisualInfo(pdpy, VisualScreenMask, &viproto, &nvi); if (!vip) { fprintf(stderr, "XpuGetColorspaceList: Internal error: vip == NULL\n"); return NULL; } for( i = 0 ; i < nvi ; i++ ) { XVisualInfo *vcurr = vip+i; char cbuff[64]; const char *class = NULL; #ifdef USE_MOZILLA_TYPES /* Workaround for the current limitation of the gfx/src/xlibrgb code * which cannot handle depths > 24bit yet */ if( vcurr->depth > 24 ) continue; #endif /* USE_MOZILLA_TYPES */ rec_count++; list = (XpuColorspaceRec *)realloc(list, sizeof(XpuColorspaceRec)*rec_count); if( !list ) return NULL; /* ToDO: This needs to be updated for the COLORSPACE X11 extension * once it is ready and approved by the XOrg arch board. */ switch (vcurr->class) { case StaticGray: class = "StaticGray"; break; case GrayScale: class = "GrayScale"; break; case StaticColor: class = "StaticColor"; break; case PseudoColor: class = "PseudoColor"; break; case TrueColor: class = "TrueColor"; break; case DirectColor: class = "DirectColor"; break; default: /* Needed for forward compatibility to the COLORSPACE extension */ sprintf (cbuff, "unknown_class_%x", vcurr->class); class = cbuff; break; } if (vcurr->bits_per_rgb == 8) { sprintf(namebuf, "%s/%dbit", class, vcurr->depth); } else { sprintf(namebuf, "%s/%dbit/%dbpg", class, vcurr->depth, vcurr->bits_per_rgb); } list[rec_count-2].name = strdup(namebuf); list[rec_count-2].visualinfo = *vcurr; } XFree((char *)vip); if( list ) { /* users: DO NOT COUNT ON THIS DETAIL * (this is only to make current impl. of XpuGetResolutionList() easier) * We may remove this implementation detail in a later revision of * the library! */ list[rec_count-1].name = NULL; rec_count--; } else { rec_count = 0; } *numEntriesPtr = rec_count; return(list); } void XpuFreeColorspaceList( XpuColorspaceList list ) { if( list ) { XpuColorspaceRec *curr = list; /* See the warning abouve about using this implementation detail for * checking for the list's end... */ while( curr->name != NULL ) { free((void *)curr->name); curr++; } free(list); } } XpuColorspaceRec * XpuFindColorspaceByName( XpuColorspaceList list, int list_count, const char *name ) { int i; for( i = 0 ; i < list_count ; i++ ) { XpuColorspaceRec *curr = &list[i]; if (!strcmp(curr->name, name)) return curr; } return(NULL); } Bool XpuGetEnableFontDownload( Display *pdpy, XPContext pcontext ) { Bool enableFontDownload; char *value; value = XpGetOneAttribute(pdpy, pcontext, XPPrinterAttr, "xp-listfonts-modes-supported"); if( !value ) { fprintf(stderr, "XpuGetEnableFontDownload: xp-listfonts-modes-supported printer attribute not found.\n"); return False; } enableFontDownload = (strstr(value, "xp-list-glyph-fonts") != NULL); XFree(value); return enableFontDownload; } int XpuSetEnableFontDownload( Display *pdpy, XPContext pcontext, Bool enableFontDownload ) { char *value, *newvalue; value = XpGetOneAttribute(pdpy, pcontext, XPPrinterAttr, "xp-listfonts-modes-supported"); if( !value ) { fprintf(stderr, "XpuSetEnableFontDownload: xp-listfonts-modes-supported printer attribute not found.\n"); return 0; /* failure */ } /* Set "xp-list-glyph-fonts" */ if( enableFontDownload ) { /* Return success if "xp-list-glyph-fonts" is already set */ if( strstr(value, "xp-list-glyph-fonts") != NULL ) { XFree(value); return 1; /* success */ } newvalue = malloc(strlen(value) + 33); if( !newvalue ) { XFree(value); return 0; /* failure */ } sprintf(newvalue, "%s xp-list-glyph-fonts", value); XpuSetOneAttribute(pdpy, pcontext, XPDocAttr, "*xp-listfonts-modes", newvalue, XPAttrMerge); free(newvalue); XFree(value); return 1; /* success */ } else { char *s, /* copy string "source" */ *d; /* copy string "destination" */ /* Return success if "xp-list-glyph-fonts" not set */ d = strstr(value, "xp-list-glyph-fonts"); if( d == NULL ) { XFree(value); return 1; /* success */ } /* strip "xp-list-glyph-fonts" from |value| */ s = d+19/*strlen("xp-list-glyph-fonts")*/; while( (*d++ = *s++) != '\0' ) ; XpuSetOneAttribute(pdpy, pcontext, XPDocAttr, "*xp-listfonts-modes", value, XPAttrMerge); XFree(value); return 1; /* success */ } } /* Return flags to indicate which attributes are supported and which not... */ static XpuSupportedFlags XpuGetSupportedAttributes( Display *pdpy, XPContext pcontext, XPAttributes type, const char *attribute_name ) { char *value; void *tok_lasts; XpuSupportedFlags flags = 0; MAKE_STRING_WRITABLE(attribute_name); if( attribute_name == NULL ) return(0); value = XpGetOneAttribute(pdpy, pcontext, type, STRING_AS_WRITABLE(attribute_name)); FREE_WRITABLE_STRING(attribute_name); if( value != NULL ) { const char *s; for( s = XpuEnumerateXpAttributeValue(value, &tok_lasts) ; s != NULL ; s = XpuEnumerateXpAttributeValue(NULL, &tok_lasts) ) { if( !strcmp(s, "job-name") ) flags |= XPUATTRIBUTESUPPORTED_JOB_NAME; else if( !strcmp(s, "job-owner") ) flags |= XPUATTRIBUTESUPPORTED_JOB_OWNER; else if( !strcmp(s, "notification-profile") ) flags |= XPUATTRIBUTESUPPORTED_NOTIFICATION_PROFILE; else if( !strcmp(s, "copy-count") ) flags |= XPUATTRIBUTESUPPORTED_COPY_COUNT; else if( !strcmp(s, "document-format") ) flags |= XPUATTRIBUTESUPPORTED_DOCUMENT_FORMAT; else if( !strcmp(s, "content-orientation") ) flags |= XPUATTRIBUTESUPPORTED_CONTENT_ORIENTATION; else if( !strcmp(s, "default-printer-resolution") ) flags |= XPUATTRIBUTESUPPORTED_DEFAULT_PRINTER_RESOLUTION; else if( !strcmp(s, "default-input-tray") ) flags |= XPUATTRIBUTESUPPORTED_DEFAULT_INPUT_TRAY; else if( !strcmp(s, "default-medium") ) flags |= XPUATTRIBUTESUPPORTED_DEFAULT_MEDIUM; else if( !strcmp(s, "plex") ) flags |= XPUATTRIBUTESUPPORTED_PLEX; else if( !strcmp(s, "xp-listfonts-modes") ) flags |= XPUATTRIBUTESUPPORTED_LISTFONTS_MODES; } XpuDisposeEnumerateXpAttributeValue(&tok_lasts); XFree(value); } return(flags); } XpuSupportedFlags XpuGetSupportedJobAttributes(Display *pdpy, XPContext pcontext) { return XpuGetSupportedAttributes(pdpy, pcontext, XPPrinterAttr, "job-attributes-supported"); } XpuSupportedFlags XpuGetSupportedDocAttributes(Display *pdpy, XPContext pcontext) { return XpuGetSupportedAttributes(pdpy, pcontext, XPPrinterAttr, "document-attributes-supported"); } XpuSupportedFlags XpuGetSupportedPageAttributes(Display *pdpy, XPContext pcontext) { return XpuGetSupportedAttributes(pdpy, pcontext, XPPrinterAttr, "xp-page-attributes-supported"); } /* Encode string for usage in a Xrm resource database as * defined in X(7): [...] To allow a Value to begin * with whitespace, the two-character sequence ``\space'' * (backslash followed by space) is recognized and replaced by * a space character, and the two-character sequence ``\tab'' * (backslash followed by horizontal tab) is recognized and * replaced by a horizontal tab character. To allow a Value to * contain embedded newline characters, the two-character * sequence ``\n'' is recognized and replaced by a newline * character. To allow a Value to be broken across multiple * lines in a text file, the two-character sequence ``\new- * line'' (backslash followed by newline) is recognized and * removed from the value. To allow a Value to contain arbi- * trary character codes, the four-character sequence ``\nnn'', * where each n is a digit character in the range of * ``0''-``7'', is recognized and replaced with a single byte * that contains the octal value specified by the sequence. * Finally, the two-character sequence ``\\'' is recognized and * replaced with a single backslash. */ char *XpuResourceEncode( const char *s ) { size_t slen; char *res; char *d; int i, c; slen = strlen(s); res = malloc(slen*4+1); if (!res) return NULL; d = res; i = slen; while (i--) { c = *s++; if (c == '\n') { if (i) { *d++ = '\\'; *d++ = 'n'; *d++ = '\\'; *d++ = '\n'; } else { *d++ = '\\'; *d++ = 'n'; } } else if (c == '\\') { *d++ = '\\'; *d++ = '\\'; } else if ((c < ' ' && c != '\t') || ((unsigned char)c >= 0x7F && (unsigned char)c < 0xA0)) { sprintf(d, "\\%03o", (unsigned char)c); d += 4; } else { *d++ = c; } } *d = '\0'; return res; } #ifdef XXXJULIEN_NOTNOW char *XpuResourceDecode( const char *str ) { } #endif /* XXXJULIEN_NOTNOW */ void XpuResourceFreeString( char *s ) { free(s); } const char *XpuXmbToCompoundText(Display *dpy, const char *xmbtext) { XTextProperty xtp; int xcr; char *xtl[2]; char *ct; if (strlen(xmbtext) == 0) return strdup(xmbtext); memset(&xtp, 0, sizeof(xtp)); xtl[0] = (char *)xmbtext; xtl[1] = NULL; xcr = XmbTextListToTextProperty(dpy, xtl, 1, XCompoundTextStyle, &xtp); if (xcr == XNoMemory || xcr == XLocaleNotSupported) { fprintf(stderr, "XpuXmbToCompoundText: XmbTextListToTextProperty failure.\n"); return strdup(xmbtext); } /* Did conversion succeed (some unconvertible characters * are not a problem) ? */ if ( !((xcr == Success) || (xcr > 0)) || (xtp.value == NULL)) { fprintf(stderr, "XpuXmbToCompoundText: XmbTextListToTextProperty failure 2.\n"); return strdup(xmbtext); } ct = malloc(xtp.nitems+1); if (!ct) { XFree(xtp.value); return NULL; } memcpy(ct, xtp.value, xtp.nitems); ct[xtp.nitems] = '\0'; XFree(xtp.value); return ct; } void XpuFreeCompundTextString( const char *s ) { free((void *)s); } const char *XpuCompoundTextToXmb(Display *dpy, const char *ct) { XTextProperty xtp; int xcr; char **xtl = NULL; int xtl_count = 0; char *xmb; int xmb_len = 0; int i; if (strlen(ct) == 0) return strdup(ct); xtp.value = (unsigned char *)ct; xtp.nitems = strlen(ct); xtp.encoding = XInternAtom(dpy, "COMPOUND_TEXT", False); xtp.format = 8; xcr = XmbTextPropertyToTextList(dpy, &xtp, &xtl, &xtl_count); if (xcr == XNoMemory || xcr == XLocaleNotSupported) { fprintf(stderr, "XpuCompoundTextToXmb: XmbTextPropertyToTextList failure 1.\n"); return strdup(ct); } /* Did conversion succeed (some unconvertible characters * are not a problem) ? */ if ( !((xcr == Success) || (xcr > 0)) || (xtl == NULL)) { fprintf(stderr, "XpuCompoundTextToXmb: XmbTextPropertyToTextList failure 2.\n"); return strdup(ct); } for (i = 0; i < xtl_count; i++) { xmb_len += strlen(xtl[i]); } xmb = malloc (xmb_len + 1); if (!xmb) { XFreeStringList(xtl); return NULL; } xmb[0] = '\0'; /* Catch zero-length case */ for (i = 0; i < xtl_count; i++) { strcat(xmb, xtl[i]); } XFreeStringList(xtl); return xmb; } void XpuFreeXmbString( const char *s ) { free((void *)s); } /* EOF. */