void
cupsdSaveAllSubscriptions(void)
{
  int			i;		/* Looping var */
  cups_file_t		*fp;		/* subscriptions.conf file */
  char			filename[1024],	/* subscriptions.conf filename */
			temp[1024];	/* Temporary string */
  cupsd_subscription_t	*sub;		/* Current subscription */
  time_t		curtime;	/* Current time */
  struct tm		*curdate;	/* Current date */
  unsigned		mask;		/* Current event mask */
  const char		*name;		/* Current event name */
  int			hex;		/* Non-zero if we are writing hex data */


 /*
  * Create the subscriptions.conf file...
  */

  snprintf(filename, sizeof(filename), "%s/subscriptions.conf", ServerRoot);

  if ((fp = cupsdCreateConfFile(filename, ConfigFilePerm)) == NULL)
    return;

  cupsdLogMessage(CUPSD_LOG_INFO, "Saving subscriptions.conf...");

 /*
  * Write a small header to the file...
  */

  curtime = time(NULL);
  curdate = localtime(&curtime);
  strftime(temp, sizeof(temp) - 1, "%Y-%m-%d %H:%M", curdate);

  cupsFilePuts(fp, "# Subscription configuration file for " CUPS_SVERSION "\n");
  cupsFilePrintf(fp, "# Written by cupsd on %s\n", temp);

  cupsFilePrintf(fp, "NextSubscriptionId %d\n", NextSubscriptionId);

 /*
  * Write every subscription known to the system...
  */

  for (sub = (cupsd_subscription_t *)cupsArrayFirst(Subscriptions);
       sub;
       sub = (cupsd_subscription_t *)cupsArrayNext(Subscriptions))
  {
    cupsFilePrintf(fp, "<Subscription %d>\n", sub->id);

    if ((name = cupsdEventName((cupsd_eventmask_t)sub->mask)) != NULL)
    {
     /*
      * Simple event list...
      */

      cupsFilePrintf(fp, "Events %s\n", name);
    }
    else
    {
     /*
      * Complex event list...
      */

      cupsFilePuts(fp, "Events");

      for (mask = 1; mask < CUPSD_EVENT_ALL; mask <<= 1)
        if (sub->mask & mask)
	  cupsFilePrintf(fp, " %s", cupsdEventName((cupsd_eventmask_t)mask));

      cupsFilePuts(fp, "\n");
    }

    if (sub->owner)
      cupsFilePrintf(fp, "Owner %s\n", sub->owner);
    if (sub->recipient)
      cupsFilePrintf(fp, "Recipient %s\n", sub->recipient);
    if (sub->job)
      cupsFilePrintf(fp, "JobId %d\n", sub->job->id);
    if (sub->dest)
      cupsFilePrintf(fp, "PrinterName %s\n", sub->dest->name);

    if (sub->user_data_len > 0)
    {
      cupsFilePuts(fp, "UserData ");

      for (i = 0, hex = 0; i < sub->user_data_len; i ++)
      {
        if (sub->user_data[i] < ' ' ||
	    sub->user_data[i] > 0x7f ||
	    sub->user_data[i] == '<')
	{
	  if (!hex)
	  {
	    cupsFilePrintf(fp, "<%02X", sub->user_data[i]);
	    hex = 1;
	  }
	  else
	    cupsFilePrintf(fp, "%02X", sub->user_data[i]);
	}
	else
	{
	  if (hex)
	  {
	    cupsFilePrintf(fp, ">%c", sub->user_data[i]);
	    hex = 0;
	  }
	  else
	    cupsFilePutChar(fp, sub->user_data[i]);
	}
      }

      if (hex)
        cupsFilePuts(fp, ">\n");
      else
        cupsFilePutChar(fp, '\n');
    }

    cupsFilePrintf(fp, "LeaseDuration %d\n", sub->lease);
    cupsFilePrintf(fp, "Interval %d\n", sub->interval);
    cupsFilePrintf(fp, "ExpirationTime %ld\n", (long)sub->expire);
    cupsFilePrintf(fp, "NextEventId %d\n", sub->next_event_id);

    cupsFilePuts(fp, "</Subscription>\n");
  }

  cupsdCloseCreatedConfFile(fp, filename);
}
static void
cupsd_send_notification(
    cupsd_subscription_t *sub,		/* I - Subscription object */
    cupsd_event_t        *event)	/* I - Event to send */
{
  ipp_state_t	state;			/* IPP event state */


  cupsdLogMessage(CUPSD_LOG_DEBUG2,
                  "cupsd_send_notification(sub=%p(%d), event=%p(%s))",
                  sub, sub->id, event, cupsdEventName(event->event));

 /*
  * Allocate the events array as needed...
  */

  if (!sub->events)
  {
    sub->events = cupsArrayNew3((cups_array_func_t)NULL, NULL,
                                (cups_ahash_func_t)NULL, 0,
				(cups_acopy_func_t)NULL,
				(cups_afree_func_t)cupsd_delete_event);

    if (!sub->events)
    {
      cupsdLogMessage(CUPSD_LOG_CRIT,
                      "Unable to allocate memory for subscription #%d!",
                      sub->id);
      return;
    }
  }

 /*
  * Purge an old event as needed...
  */

  if (cupsArrayCount(sub->events) >= MaxEvents)
  {
   /*
    * Purge the oldest event in the cache...
    */

    cupsArrayRemove(sub->events, cupsArrayFirst(sub->events));

    sub->first_event_id ++;
  }

 /*
  * Add the event to the subscription.  Since the events array is
  * always MaxEvents in length, and since we will have already
  * removed an event from the subscription cache if we hit the
  * event cache limit, we don't need to check for overflow here...
  */

  cupsArrayAdd(sub->events, event);

 /*
  * Deliver the event...
  */

  if (sub->recipient)
  {
    for (;;)
    {
      if (sub->pipe < 0)
	cupsd_start_notifier(sub);

      cupsdLogMessage(CUPSD_LOG_DEBUG2, "sub->pipe=%d", sub->pipe);

      if (sub->pipe < 0)
	break;

      event->attrs->state = IPP_IDLE;

      while ((state = ippWriteFile(sub->pipe, event->attrs)) != IPP_DATA)
        if (state == IPP_ERROR)
	  break;

      if (state == IPP_ERROR)
      {
        if (errno == EPIPE)
	{
	 /*
	  * Notifier died, try restarting it...
	  */

          cupsdLogMessage(CUPSD_LOG_WARN,
	                  "Notifier for subscription %d (%s) went away, "
			  "retrying!",
			  sub->id, sub->recipient);
	  cupsdEndProcess(sub->pid, 0);

	  close(sub->pipe);
	  sub->pipe = -1;
          continue;
	}

        cupsdLogMessage(CUPSD_LOG_ERROR,
	                "Unable to send event for subscription %d (%s)!",
			sub->id, sub->recipient);
      }

     /*
      * If we get this far, break out of the loop...
      */

      break;
    }
  }

 /*
  * Bump the event sequence number...
  */

  sub->next_event_id ++;
}
Beispiel #3
0
int					/* O - 1 on success, 0 on error */
translate_messages(cups_array_t *cat,	/* I - Message catalog */
                   const char *lang)	/* I - Output language... */
{
 /*
  * Google provides a simple translation/language tool for translating
  * from one language to another.  It is far from perfect, however it
  * can be used to get a basic translation done or update an existing
  * translation when no other resources are available.
  *
  * Translation requests are sent as HTTP POSTs to
  * "http://translate.google.com/translate_t" with the following form
  * variables:
  *
  *   Name      Description                         Value
  *   --------  ----------------------------------  ----------------
  *   hl        Help language?                      "en"
  *   ie        Input encoding                      "UTF8"
  *   langpair  Language pair                       "en|" + language
  *   oe        Output encoding                     "UTF8"
  *   text      Text to translate                   translation string
  */

  int		ret;			/* Return value */
  _cups_message_t *m;			/* Current message */
  int		tries;			/* Number of tries... */
  http_t	*http;			/* HTTP connection */
  http_status_t	status;			/* Status of POST request */
  char		*idptr,			/* Pointer into msgid */
		buffer[65536],		/* Input/output buffer */
		*bufptr,		/* Pointer into buffer */
		*bufend,		/* Pointer to end of buffer */
		length[16];		/* Content length */
  int		bytes;			/* Number of bytes read */


 /*
  * Connect to translate.google.com...
  */

  puts("Connecting to translate.google.com...");

  if ((http = httpConnect("translate.google.com", 80)) == NULL)
  {
    perror("Unable to connect to translate.google.com");
    return (0);
  }

 /*
  * Scan the current messages, requesting a translation of any untranslated
  * messages...
  */

  for (m = (_cups_message_t *)cupsArrayFirst(cat), ret = 1;
       m;
       m = (_cups_message_t *)cupsArrayNext(cat))
  {
   /*
    * Skip messages that are already translated...
    */

    if (m->str && m->str[0])
      continue;

   /*
    * Encode the form data into the buffer...
    */

    snprintf(buffer, sizeof(buffer),
             "hl=en&ie=UTF8&langpair=en|%s&oe=UTF8&text=", lang);
    bufptr = buffer + strlen(buffer);
    bufend = buffer + sizeof(buffer) - 5;

    for (idptr = m->id; *idptr && bufptr < bufend; idptr ++)
      if (*idptr == ' ')
        *bufptr++ = '+';
      else if (*idptr < ' ' || *idptr == '%')
      {
        sprintf(bufptr, "%%%02X", *idptr & 255);
	bufptr += 3;
      }
      else if (*idptr != '&')
        *bufptr++ = *idptr;

    *bufptr++ = '&';
    *bufptr = '\0';

    sprintf(length, "%d", (int)(bufptr - buffer));

   /*
    * Send the request...
    */

    printf("\"%s\" = ", m->id);
    fflush(stdout);

    tries = 0;

    do
    {
      httpClearFields(http);
      httpSetField(http, HTTP_FIELD_CONTENT_TYPE,
                   "application/x-www-form-urlencoded");
      httpSetField(http, HTTP_FIELD_CONTENT_LENGTH, length);

      if (httpPost(http, "/translate_t"))
      {
	httpReconnect(http);
	httpPost(http, "/translate_t");
      }

      httpWrite2(http, buffer, bufptr - buffer);

      while ((status = httpUpdate(http)) == HTTP_CONTINUE);

      if (status != HTTP_OK && status != HTTP_ERROR)
        httpFlush(http);

      tries ++;
    }
    while (status == HTTP_ERROR && tries < 10);

    if (status == HTTP_OK)
    {
     /*
      * OK, read the translation back...
      */

      bufptr = buffer;
      bufend = buffer + sizeof(buffer) - 1;

      while ((bytes = httpRead2(http, bufptr, bufend - bufptr)) > 0)
        bufptr += bytes;

      if (bytes < 0)
      {
       /*
        * Read error, abort!
	*/

        puts("READ ERROR!");
	ret = 0;
	break;
      }

      *bufptr = '\0';

     /*
      * Find the div containing translation
      */

      if ((bufptr = strstr(buffer, "<div id=result_box")) == NULL)
      {
       /*
        * No textarea, abort!
	*/

        puts("NO div id=result_box!");
	ret = 0;
	break;
      }

      if ((bufptr = strchr(bufptr, '>')) == NULL)
      {
       /*
        * textarea doesn't end, abort!
	*/

        puts("DIV SHORT DATA!");
	ret = 0;
	break;
      }

      bufptr ++;

      if ((bufend = strstr(bufptr, "</div>")) == NULL)
      {
       /*
        * textarea doesn't close, abort!
	*/

        puts("/DIV SHORT DATA!");
	ret = 0;
	break;
      }

      *bufend = '\0';

     /*
      * Copy the translation...
      */

      m->str = strdup(bufptr);

     /*
      * Convert character entities to regular chars...
      */

      for (bufptr = strchr(m->str, '&');
           bufptr;
	   bufptr = strchr(bufptr + 1, '&'))
      {
        if (!strncmp(bufptr, "&lt;", 4))
	{
	  *bufptr = '<';
	  _cups_strcpy(bufptr + 1, bufptr + 4);
	}
        else if (!strncmp(bufptr, "&gt;", 4))
	{
	  *bufptr = '>';
	  _cups_strcpy(bufptr + 1, bufptr + 4);
	}
        else if (!strncmp(bufptr, "&amp;", 5))
	  _cups_strcpy(bufptr + 1, bufptr + 5);
      }

      printf("\"%s\"\n", m->str);
    }
    else if (status == HTTP_ERROR)
    {
      printf("NETWORK ERROR (%s)!\n", strerror(httpError(http)));
      ret = 0;
      break;
    }
    else
    {
      printf("HTTP ERROR %d!\n", status);
      ret = 0;
      break;
    }
  }

  httpClose(http);

  return (ret);
}
Beispiel #4
0
static void
write_nodes(const char   *path,		/* I - File to write */
            help_index_t *hi)		/* I - Index of files */
{
  cups_file_t	*fp;			/* Output file */
  int		id;			/* Current node ID */
  help_node_t	*node;			/* Current help node */
  int		subnodes;		/* Currently in Subnodes for file? */
  int		needclose;		/* Need to close the current node? */


  if ((fp = cupsFileOpen(path, "w")) == NULL)
  {
    fprintf(stderr, "makedocset: Unable to create %s: %s\n", path,
            strerror(errno));
    exit(1);
  }

  cupsFilePuts(fp, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
		   "<DocSetNodes version=\"1.0\">\n"
		   "<TOC>\n"
		   "<Node id=\"0\">\n"
		   "<Name>CUPS Documentation</Name>\n"
		   "<Path>Documentation/index.html</Path>\n"
		   "</Node>\n");

  for (node = (help_node_t *)cupsArrayFirst(hi->nodes), id = 1, subnodes = 0,
           needclose = 0;
       node;
       node = (help_node_t *)cupsArrayNext(hi->nodes), id ++)
  {
    if (node->anchor)
    {
      if (!subnodes)
      {
        cupsFilePuts(fp, "<Subnodes>\n");
	subnodes = 1;
      }

      cupsFilePrintf(fp, "<Node id=\"%d\">\n"
                         "<Path>Documentation/%s</Path>\n"
			 "<Anchor>%s</Anchor>\n"
			 "<Name>%s</Name>\n"
			 "</Node>\n", id, node->filename, node->anchor,
		     node->text);
    }
    else
    {
      if (subnodes)
      {
        cupsFilePuts(fp, "</Subnodes>\n");
	subnodes = 0;
      }

      if (needclose)
        cupsFilePuts(fp, "</Node>\n");

      cupsFilePrintf(fp, "<Node id=\"%d\">\n"
                         "<Path>Documentation/%s</Path>\n"
			 "<Name>%s</Name>\n", id, node->filename, node->text);
      needclose = 1;
    }
  }

  if (subnodes)
    cupsFilePuts(fp, "</Subnodes>\n");

  if (needclose)
    cupsFilePuts(fp, "</Node>\n");

  cupsFilePuts(fp, "</TOC>\n"
		   "</DocSetNodes>\n");

  cupsFileClose(fp);
}
Beispiel #5
0
Datei: rss.c Projekt: ezeep/cups
int					/* O - Exit status */
main(int  argc,				/* I - Number of command-line arguments */
     char *argv[])			/* I - Command-line arguments */
{
  int		i;			/* Looping var */
  ipp_t		*event;			/* Event from scheduler */
  ipp_state_t	state;			/* IPP event state */
  char		scheme[32],		/* URI scheme ("rss") */
		username[256],		/* Username for remote RSS */
		host[1024],		/* Hostname for remote RSS */
		resource[1024],		/* RSS file */
		*options;		/* Options */
  int		port,			/* Port number for remote RSS */
		max_events;		/* Maximum number of events */
  http_t	*http;			/* Connection to remote server */
  http_status_t	status;			/* HTTP GET/PUT status code */
  char		filename[1024],		/* Local filename */
		newname[1024];		/* filename.N */
  cups_lang_t	*language;		/* Language information */
  ipp_attribute_t *printer_up_time,	/* Timestamp on event */
		*notify_sequence_number,/* Sequence number */
		*notify_printer_uri;	/* Printer URI */
  char		*subject,		/* Subject for notification message */
		*text,			/* Text for notification message */
		link_url[1024],		/* Link to printer */
		link_scheme[32],	/* Scheme for link */
		link_username[256],	/* Username for link */
		link_host[1024],	/* Host for link */
		link_resource[1024];	/* Resource for link */
  int		link_port;		/* Link port */
  cups_array_t	*rss;			/* RSS message array */
  _cups_rss_t	*msg;			/* RSS message */
  char		baseurl[1024];		/* Base URL */
  fd_set	input;			/* Input set for select() */
  struct timeval timeout;		/* Timeout for select() */
  int		changed;		/* Has the RSS data changed? */
  int		exit_status;		/* Exit status */


  fprintf(stderr, "DEBUG: argc=%d\n", argc);
  for (i = 0; i < argc; i ++)
    fprintf(stderr, "DEBUG: argv[%d]=\"%s\"\n", i, argv[i]);

 /*
  * See whether we are publishing this RSS feed locally or remotely...
  */

  if (httpSeparateURI(HTTP_URI_CODING_ALL, argv[1], scheme, sizeof(scheme),
                      username, sizeof(username), host, sizeof(host), &port,
		      resource, sizeof(resource)) < HTTP_URI_OK)
  {
    fprintf(stderr, "ERROR: Bad RSS URI \"%s\"!\n", argv[1]);
    return (1);
  }

  max_events = 20;

  if ((options = strchr(resource, '?')) != NULL)
  {
    *options++ = '\0';

    if (!strncmp(options, "max_events=", 11))
    {
      max_events = atoi(options + 11);

      if (max_events <= 0)
        max_events = 20;
    }
  }

  rss = cupsArrayNew((cups_array_func_t)compare_rss, NULL);

  if (host[0])
  {
   /*
    * Remote feed, see if we can get the current file...
    */

    int	fd;				/* Temporary file */


    if ((rss_password = strchr(username, ':')) != NULL)
      *rss_password++ = '\0';

    cupsSetPasswordCB(password_cb);
    cupsSetUser(username);

    if ((fd = cupsTempFd(filename, sizeof(filename))) < 0)
    {
      fprintf(stderr, "ERROR: Unable to create temporary file: %s\n",
              strerror(errno));

      return (1);
    }

    if ((http = httpConnect(host, port)) == NULL)
    {
      fprintf(stderr, "ERROR: Unable to connect to %s on port %d: %s\n",
              host, port, strerror(errno));

      close(fd);
      unlink(filename);

      return (1);
    }

    status = cupsGetFd(http, resource, fd);

    close(fd);

    if (status != HTTP_OK && status != HTTP_NOT_FOUND)
    {
      fprintf(stderr, "ERROR: Unable to GET %s from %s on port %d: %d %s\n",
	      resource, host, port, status, httpStatus(status));

      httpClose(http);
      unlink(filename);

      return (1);
    }

    strlcpy(newname, filename, sizeof(newname));

    httpAssembleURI(HTTP_URI_CODING_ALL, baseurl, sizeof(baseurl), "http",
                    NULL, host, port, resource);
  }
  else
  {
    const char	*cachedir,		/* CUPS_CACHEDIR */
		*server_name,		/* SERVER_NAME */
		*server_port;		/* SERVER_PORT */


    http = NULL;

    if ((cachedir = getenv("CUPS_CACHEDIR")) == NULL)
      cachedir = CUPS_CACHEDIR;

    if ((server_name = getenv("SERVER_NAME")) == NULL)
      server_name = "localhost";

    if ((server_port = getenv("SERVER_PORT")) == NULL)
      server_port = "631";

    snprintf(filename, sizeof(filename), "%s/rss%s", cachedir, resource);
    snprintf(newname, sizeof(newname), "%s.N", filename);

    httpAssembleURIf(HTTP_URI_CODING_ALL, baseurl, sizeof(baseurl), "http",
                     NULL, server_name, atoi(server_port), "/rss%s", resource);
  }

 /*
  * Load the previous RSS file, if any...
  */

  load_rss(rss, filename);

  changed = cupsArrayCount(rss) == 0;

 /*
  * Localize for the user's chosen language...
  */

  language = cupsLangDefault();

 /*
  * Read events and update the RSS file until we are out of events.
  */

  for (exit_status = 0, event = NULL;;)
  {
    if (changed)
    {
     /*
      * Save the messages to the file again, uploading as needed...
      */

      if (save_rss(rss, newname, baseurl))
      {
	if (http)
	{
	 /*
          * Upload the RSS file...
	  */

          if ((status = cupsPutFile(http, resource, filename)) != HTTP_CREATED)
            fprintf(stderr, "ERROR: Unable to PUT %s from %s on port %d: %d %s\n",
	            resource, host, port, status, httpStatus(status));
	}
	else
	{
	 /*
          * Move the new RSS file over top the old one...
	  */

          if (rename(newname, filename))
            fprintf(stderr, "ERROR: Unable to rename %s to %s: %s\n",
	            newname, filename, strerror(errno));
	}

	changed = 0;
      }
    }

   /*
    * Wait up to 30 seconds for an event...
    */

    timeout.tv_sec  = 30;
    timeout.tv_usec = 0;

    FD_ZERO(&input);
    FD_SET(0, &input);

    if (select(1, &input, NULL, NULL, &timeout) < 0)
      continue;
    else if (!FD_ISSET(0, &input))
    {
      fprintf(stderr, "DEBUG: %s is bored, exiting...\n", argv[1]);
      break;
    }

   /*
    * Read the next event...
    */

    event = ippNew();
    while ((state = ippReadFile(0, event)) != IPP_DATA)
    {
      if (state <= IPP_IDLE)
        break;
    }

    if (state == IPP_ERROR)
      fputs("DEBUG: ippReadFile() returned IPP_ERROR!\n", stderr);

    if (state <= IPP_IDLE)
      break;

   /*
    * Collect the info from the event...
    */

    printer_up_time        = ippFindAttribute(event, "printer-up-time",
                                              IPP_TAG_INTEGER);
    notify_sequence_number = ippFindAttribute(event, "notify-sequence-number",
                                	      IPP_TAG_INTEGER);
    notify_printer_uri     = ippFindAttribute(event, "notify-printer-uri",
                                	      IPP_TAG_URI);
    subject                = cupsNotifySubject(language, event);
    text                   = cupsNotifyText(language, event);

    if (printer_up_time && notify_sequence_number && subject && text)
    {
     /*
      * Create a new RSS message...
      */

      if (notify_printer_uri)
      {
        httpSeparateURI(HTTP_URI_CODING_ALL,
	                notify_printer_uri->values[0].string.text,
			link_scheme, sizeof(link_scheme),
                        link_username, sizeof(link_username),
			link_host, sizeof(link_host), &link_port,
		        link_resource, sizeof(link_resource));
        httpAssembleURI(HTTP_URI_CODING_ALL, link_url, sizeof(link_url),
	                "http", link_username, link_host, link_port,
			link_resource);
      }

      msg = new_message(notify_sequence_number->values[0].integer,
                        xml_escape(subject), xml_escape(text),
			notify_printer_uri ? xml_escape(link_url) : NULL,
			printer_up_time->values[0].integer);

      if (!msg)
      {
        fprintf(stderr, "ERROR: Unable to create message: %s\n",
	        strerror(errno));
        exit_status = 1;
	break;
      }

     /*
      * Add it to the array...
      */

      cupsArrayAdd(rss, msg);

      changed = 1;

     /*
      * Trim the array as needed...
      */

      while (cupsArrayCount(rss) > max_events)
      {
        msg = cupsArrayFirst(rss);

	cupsArrayRemove(rss, msg);

	delete_message(msg);
      }
    }

    if (subject)
      free(subject);

    if (text)
      free(text);

    ippDelete(event);
    event = NULL;
  }

 /*
  * We only get here when idle or error...
  */

  ippDelete(event);

  if (http)
  {
    unlink(filename);
    httpClose(http);
  }

  return (exit_status);
}
Beispiel #6
0
char *					/* O - String containing option code or @code NULL@ if there is no option code */
ppdEmitString(ppd_file_t    *ppd,	/* I - PPD file record */
              ppd_section_t section,	/* I - Section to write */
              float         min_order)	/* I - Lowest OrderDependency */
{
    int		i, j,			/* Looping vars */
            count;			/* Number of choices */
    ppd_choice_t	**choices;		/* Choices */
    ppd_size_t	*size;			/* Custom page size */
    ppd_coption_t	*coption;		/* Custom option */
    ppd_cparam_t	*cparam;		/* Custom parameter */
    size_t	bufsize;		/* Size of string buffer needed */
    char		*buffer,		/* String buffer */
                *bufptr,		/* Pointer into buffer */
                *bufend;		/* End of buffer */
    struct lconv	*loc;			/* Locale data */


    DEBUG_printf(("ppdEmitString(ppd=%p, section=%d, min_order=%f)",
                  ppd, section, min_order));

    /*
     * Range check input...
     */

    if (!ppd)
        return (NULL);

    /*
     * Use PageSize or PageRegion as required...
     */

    ppd_handle_media(ppd);

    /*
     * Collect the options we need to emit...
     */

    if ((count = ppdCollect2(ppd, section, min_order, &choices)) == 0)
        return (NULL);

    /*
     * Count the number of bytes that are required to hold all of the
     * option code...
     */

    for (i = 0, bufsize = 1; i < count; i ++)
    {
        if (section == PPD_ORDER_JCL)
        {
            if (!_cups_strcasecmp(choices[i]->choice, "Custom") &&
                    (coption = ppdFindCustomOption(ppd, choices[i]->option->keyword))
                    != NULL)
            {
                /*
                 * Add space to account for custom parameter substitution...
                */

                for (cparam = (ppd_cparam_t *)cupsArrayFirst(coption->params);
                        cparam;
                        cparam = (ppd_cparam_t *)cupsArrayNext(coption->params))
                {
                    switch (cparam->type)
                    {
                    case PPD_CUSTOM_CURVE :
                    case PPD_CUSTOM_INVCURVE :
                    case PPD_CUSTOM_POINTS :
                    case PPD_CUSTOM_REAL :
                    case PPD_CUSTOM_INT :
                        bufsize += 10;
                        break;

                    case PPD_CUSTOM_PASSCODE :
                    case PPD_CUSTOM_PASSWORD :
                    case PPD_CUSTOM_STRING :
                        if (cparam->current.custom_string)
                            bufsize += strlen(cparam->current.custom_string);
                        break;
                    }
                }
            }
        }
        else if (section != PPD_ORDER_EXIT)
        {
            bufsize += 3;			/* [{\n */

            if ((!_cups_strcasecmp(choices[i]->option->keyword, "PageSize") ||
                    !_cups_strcasecmp(choices[i]->option->keyword, "PageRegion")) &&
                    !_cups_strcasecmp(choices[i]->choice, "Custom"))
            {
                DEBUG_puts("2ppdEmitString: Custom size set!");

                bufsize += 37;			/* %%BeginFeature: *CustomPageSize True\n */
                bufsize += 50;			/* Five 9-digit numbers + newline */
            }
            else if (!_cups_strcasecmp(choices[i]->choice, "Custom") &&
                     (coption = ppdFindCustomOption(ppd,
                                                    choices[i]->option->keyword))
                     != NULL)
            {
                bufsize += 23 + strlen(choices[i]->option->keyword) + 6;
                /* %%BeginFeature: *Customkeyword True\n */


                for (cparam = (ppd_cparam_t *)cupsArrayFirst(coption->params);
                        cparam;
                        cparam = (ppd_cparam_t *)cupsArrayNext(coption->params))
                {
                    switch (cparam->type)
                    {
                    case PPD_CUSTOM_CURVE :
                    case PPD_CUSTOM_INVCURVE :
                    case PPD_CUSTOM_POINTS :
                    case PPD_CUSTOM_REAL :
                    case PPD_CUSTOM_INT :
                        bufsize += 10;
                        break;

                    case PPD_CUSTOM_PASSCODE :
                    case PPD_CUSTOM_PASSWORD :
                    case PPD_CUSTOM_STRING :
                        bufsize += 3;
                        if (cparam->current.custom_string)
                            bufsize += 4 * strlen(cparam->current.custom_string);
                        break;
                    }
                }
            }
            else
                bufsize += 17 + strlen(choices[i]->option->keyword) + 1 +
                           strlen(choices[i]->choice) + 1;
            /* %%BeginFeature: *keyword choice\n */

            bufsize += 13;			/* %%EndFeature\n */
            bufsize += 22;			/* } stopped cleartomark\n */
        }

        if (choices[i]->code)
            bufsize += strlen(choices[i]->code) + 1;
        else
            bufsize += strlen(ppd_custom_code);
    }

    /*
     * Allocate memory...
     */

    DEBUG_printf(("2ppdEmitString: Allocating %d bytes for string...",
                  (int)bufsize));

    if ((buffer = calloc(1, bufsize)) == NULL)
    {
        free(choices);
        return (NULL);
    }

    bufend = buffer + bufsize - 1;
    //loc    = localeconv();

    /*
     * Copy the option code to the buffer...
     */

    for (i = 0, bufptr = buffer; i < count; i ++, bufptr += strlen(bufptr))
        if (section == PPD_ORDER_JCL)
        {
            if (!_cups_strcasecmp(choices[i]->choice, "Custom") &&
                    choices[i]->code &&
                    (coption = ppdFindCustomOption(ppd, choices[i]->option->keyword))
                    != NULL)
            {
                /*
                 * Handle substitutions in custom JCL options...
                */

                char	*cptr;			/* Pointer into code */
                int	pnum;			/* Parameter number */


                for (cptr = choices[i]->code; *cptr && bufptr < bufend;)
                {
                    if (*cptr == '\\')
                    {
                        cptr ++;

                        if (isdigit(*cptr & 255))
                        {
                            /*
                             * Substitute parameter...
                             */

                            pnum = *cptr++ - '0';
                            while (isdigit(*cptr & 255))
                                pnum = pnum * 10 + *cptr++ - '0';

                            for (cparam = (ppd_cparam_t *)cupsArrayFirst(coption->params);
                                    cparam;
                                    cparam = (ppd_cparam_t *)cupsArrayNext(coption->params))
                                if (cparam->order == pnum)
                                    break;

                            if (cparam)
                            {
                                switch (cparam->type)
                                {
                                case PPD_CUSTOM_CURVE :
                                case PPD_CUSTOM_INVCURVE :
                                case PPD_CUSTOM_POINTS :
                                case PPD_CUSTOM_REAL :
                                    bufptr = _cupsStrFormatd(bufptr, bufend,
                                                             cparam->current.custom_real,
                                                             loc);
                                    break;

                                case PPD_CUSTOM_INT :
                                    snprintf(bufptr, bufend - bufptr, "%d",
                                             cparam->current.custom_int);
                                    bufptr += strlen(bufptr);
                                    break;

                                case PPD_CUSTOM_PASSCODE :
                                case PPD_CUSTOM_PASSWORD :
                                case PPD_CUSTOM_STRING :
                                    if (cparam->current.custom_string)
                                    {
                                        strlcpy(bufptr, cparam->current.custom_string,
                                                bufend - bufptr);
                                        bufptr += strlen(bufptr);
                                    }
                                    break;
                                }
                            }
                        }
                        else if (*cptr)
                            *bufptr++ = *cptr++;
                    }
                    else
                        *bufptr++ = *cptr++;
                }
            }
            else
            {
                /*
                 * Otherwise just copy the option code directly...
                */

                strlcpy(bufptr, choices[i]->code, bufend - bufptr + 1);
                bufptr += strlen(bufptr);
            }
        }
        else if (section != PPD_ORDER_EXIT)
        {
            /*
             * Add wrapper commands to prevent printer errors for unsupported
             * options...
             */

            strlcpy(bufptr, "[{\n", bufend - bufptr + 1);
            bufptr += 3;

            /*
             * Send DSC comments with option...
             */

            DEBUG_printf(("2ppdEmitString: Adding code for %s=%s...",
                          choices[i]->option->keyword, choices[i]->choice));

            if ((!_cups_strcasecmp(choices[i]->option->keyword, "PageSize") ||
                    !_cups_strcasecmp(choices[i]->option->keyword, "PageRegion")) &&
                    !_cups_strcasecmp(choices[i]->choice, "Custom"))
            {
                /*
                 * Variable size; write out standard size options, using the
                * parameter positions defined in the PPD file...
                */

                ppd_attr_t	*attr;		/* PPD attribute */
                int		pos,		/* Position of custom value */
                        orientation;	/* Orientation to use */
                float		values[5];	/* Values for custom command */


                strlcpy(bufptr, "%%BeginFeature: *CustomPageSize True\n",
                        bufend - bufptr + 1);
                bufptr += 37;

                size = ppdPageSize(ppd, "Custom");

                memset(values, 0, sizeof(values));

                if ((attr = ppdFindAttr(ppd, "ParamCustomPageSize", "Width")) != NULL)
                {
                    pos = atoi(attr->value) - 1;

                    if (pos < 0 || pos > 4)
                        pos = 0;
                }
                else
                    pos = 0;

                values[pos] = size->width;

                if ((attr = ppdFindAttr(ppd, "ParamCustomPageSize", "Height")) != NULL)
                {
                    pos = atoi(attr->value) - 1;

                    if (pos < 0 || pos > 4)
                        pos = 1;
                }
                else
                    pos = 1;

                values[pos] = size->length;

                /*
                 * According to the Adobe PPD specification, an orientation of 1
                * will produce a print that comes out upside-down with the X
                * axis perpendicular to the direction of feed, which is exactly
                * what we want to be consistent with non-PS printers.
                *
                * We could also use an orientation of 3 to produce output that
                * comes out rightside-up (this is the default for many large format
                * printer PPDs), however for consistency we will stick with the
                * value 1.
                *
                * If we wanted to get fancy, we could use orientations of 0 or
                * 2 and swap the width and length, however we don't want to get
                * fancy, we just want it to work consistently.
                *
                * The orientation value is range limited by the Orientation
                * parameter definition, so certain non-PS printer drivers that
                * only support an Orientation of 0 will get the value 0 as
                * expected.
                */

                orientation = 1;

                if ((attr = ppdFindAttr(ppd, "ParamCustomPageSize",
                                        "Orientation")) != NULL)
                {
                    int min_orient, max_orient;	/* Minimum and maximum orientations */


                    if (sscanf(attr->value, "%d%*s%d%d", &pos, &min_orient,
                               &max_orient) != 3)
                        pos = 4;
                    else
                    {
                        pos --;

                        if (pos < 0 || pos > 4)
                            pos = 4;

                        if (orientation > max_orient)
                            orientation = max_orient;
                        else if (orientation < min_orient)
                            orientation = min_orient;
                    }
                }
                else
                    pos = 4;

                values[pos] = (float)orientation;

                for (pos = 0; pos < 5; pos ++)
                {
                    bufptr    = _cupsStrFormatd(bufptr, bufend, values[pos], loc);
                    *bufptr++ = '\n';
                }

                if (!choices[i]->code)
                {
                    /*
                     * This can happen with certain buggy PPD files that don't include
                     * a CustomPageSize command sequence...  We just use a generic
                     * Level 2 command sequence...
                     */

                    strlcpy(bufptr, ppd_custom_code, bufend - bufptr + 1);
                    bufptr += strlen(bufptr);
                }
            }
            else if (!_cups_strcasecmp(choices[i]->choice, "Custom") &&
                     (coption = ppdFindCustomOption(ppd, choices[i]->option->keyword))
                     != NULL)
            {
                /*
                 * Custom option...
                */

                const char	*s;		/* Pointer into string value */
                cups_array_t	*params;	/* Parameters in the correct output order */


                params = cupsArrayNew((cups_array_func_t)ppd_compare_cparams, NULL);

                for (cparam = (ppd_cparam_t *)cupsArrayFirst(coption->params);
                        cparam;
                        cparam = (ppd_cparam_t *)cupsArrayNext(coption->params))
                    cupsArrayAdd(params, cparam);

                snprintf(bufptr, bufend - bufptr + 1,
                         "%%%%BeginFeature: *Custom%s True\n", coption->keyword);
                bufptr += strlen(bufptr);

                for (cparam = (ppd_cparam_t *)cupsArrayFirst(params);
                        cparam;
                        cparam = (ppd_cparam_t *)cupsArrayNext(params))
                {
                    switch (cparam->type)
                    {
                    case PPD_CUSTOM_CURVE :
                    case PPD_CUSTOM_INVCURVE :
                    case PPD_CUSTOM_POINTS :
                    case PPD_CUSTOM_REAL :
                        bufptr    = _cupsStrFormatd(bufptr, bufend,
                                                    cparam->current.custom_real, loc);
                        *bufptr++ = '\n';
                        break;

                    case PPD_CUSTOM_INT :
                        snprintf(bufptr, bufend - bufptr + 1, "%d\n",
                                 cparam->current.custom_int);
                        bufptr += strlen(bufptr);
                        break;

                    case PPD_CUSTOM_PASSCODE :
                    case PPD_CUSTOM_PASSWORD :
                    case PPD_CUSTOM_STRING :
                        *bufptr++ = '(';

                        if (cparam->current.custom_string)
                        {
                            for (s = cparam->current.custom_string; *s; s ++)
                            {
                                if (*s < ' ' || *s == '(' || *s == ')' || *s >= 127)
                                {
                                    snprintf(bufptr, bufend - bufptr + 1, "\\%03o", *s & 255);
                                    bufptr += strlen(bufptr);
                                }
                                else
                                    *bufptr++ = *s;
                            }
                        }

                        *bufptr++ = ')';
                        *bufptr++ = '\n';
                        break;
                    }
                }

                cupsArrayDelete(params);
            }
            else
            {
                snprintf(bufptr, bufend - bufptr + 1, "%%%%BeginFeature: *%s %s\n",
                         choices[i]->option->keyword, choices[i]->choice);
                bufptr += strlen(bufptr);
            }

            if (choices[i]->code && choices[i]->code[0])
            {
                j = (int)strlen(choices[i]->code);
                memcpy(bufptr, choices[i]->code, j);
                bufptr += j;

                if (choices[i]->code[j - 1] != '\n')
                    *bufptr++ = '\n';
            }

            strlcpy(bufptr, "%%EndFeature\n"
                    "} stopped cleartomark\n", bufend - bufptr + 1);
            bufptr += strlen(bufptr);

            DEBUG_printf(("2ppdEmitString: Offset in string is %d...",
                          (int)(bufptr - buffer)));
        }
        else
        {
            strlcpy(bufptr, choices[i]->code, bufend - bufptr + 1);
            bufptr += strlen(bufptr);
        }

    /*
     * Nul-terminate, free, and return...
     */

    *bufptr = '\0';

    free(choices);

    return (buffer);
}
Beispiel #7
0
static void
probe_device(snmp_cache_t *device)	/* I - Device */
{
  char		uri[1024],		/* Full device URI */
		*uriptr,		/* Pointer into URI */
		*format;		/* Format string for device */
  device_uri_t	*device_uri;		/* Current DeviceURI match */


  debug_printf("DEBUG: %.3f Probing %s...\n", run_time(), device->addrname);

#ifdef __APPLE__
 /*
  * If the printer supports Bonjour/mDNS, don't report it from the SNMP backend.
  */

  if (!try_connect(&(device->address), device->addrname, 5353))
  {
    debug_printf("DEBUG: %s supports mDNS, not reporting!\n", device->addrname);
    return;
  }
#endif /* __APPLE__ */

 /*
  * Lookup the device in the match table...
  */

  for (device_uri = (device_uri_t *)cupsArrayFirst(DeviceURIs);
       device_uri;
       device_uri = (device_uri_t *)cupsArrayNext(DeviceURIs))
    if (device->make_and_model &&
        !regexec(&(device_uri->re), device->make_and_model, 0, NULL, 0))
    {
     /*
      * Found a match, add the URIs...
      */

      for (format = (char *)cupsArrayFirst(device_uri->uris);
           format;
	   format = (char *)cupsArrayNext(device_uri->uris))
      {
        for (uriptr = uri; *format && uriptr < (uri + sizeof(uri) - 1);)
	  if (*format == '%' && format[1] == 's')
	  {
	   /*
	    * Insert hostname/address...
	    */

	    strlcpy(uriptr, device->addrname, sizeof(uri) - (size_t)(uriptr - uri));
	    uriptr += strlen(uriptr);
	    format += 2;
	  }
	  else
	    *uriptr++ = *format++;

        *uriptr = '\0';

        update_cache(device, uri, NULL, NULL);
      }

      return;
    }

 /*
  * Then try the standard ports...
  */

  if (!try_connect(&(device->address), device->addrname, 9100))
  {
    debug_printf("DEBUG: %s supports AppSocket!\n", device->addrname);

    snprintf(uri, sizeof(uri), "socket://%s", device->addrname);
    update_cache(device, uri, NULL, NULL);
  }
  else if (!try_connect(&(device->address), device->addrname, 515))
  {
    debug_printf("DEBUG: %s supports LPD!\n", device->addrname);

    snprintf(uri, sizeof(uri), "lpd://%s/", device->addrname);
    update_cache(device, uri, NULL, NULL);
  }
}
Beispiel #8
0
static void
dnssdUpdateDNSSDName(int from_callback)	/* I - Called from callback? */
{
  char		webif[1024];		/* Web interface share name */
#  ifdef __APPLE__
  SCDynamicStoreRef sc;			/* Context for dynamic store */
  CFDictionaryRef btmm;			/* Back-to-My-Mac domains */
  CFStringEncoding nameEncoding;	/* Encoding of computer name */
  CFStringRef	nameRef;		/* Host name CFString */
  char		nameBuffer[1024];	/* C-string buffer */
#  endif /* __APPLE__ */


 /*
  * Only share the web interface and printers when non-local listening is
  * enabled...
  */

  if (!DNSSDPort)
  {
   /*
    * Get the port we use for registrations.  If we are not listening on any
    * non-local ports, there is no sense sharing local printers via Bonjour...
    */

    cupsd_listener_t	*lis;		/* Current listening socket */

    for (lis = (cupsd_listener_t *)cupsArrayFirst(Listeners);
	 lis;
	 lis = (cupsd_listener_t *)cupsArrayNext(Listeners))
    {
      if (httpAddrLocalhost(&(lis->address)))
	continue;

      DNSSDPort = httpAddrPort(&(lis->address));
      break;
    }
  }

  if (!DNSSDPort)
    return;

 /*
  * Get the computer name as a c-string...
  */

#  ifdef __APPLE__
  sc = SCDynamicStoreCreate(kCFAllocatorDefault, CFSTR("cupsd"), NULL, NULL);

  if (sc)
  {
   /*
    * Get the computer name from the dynamic store...
    */

    cupsdClearString(&DNSSDComputerName);

    if ((nameRef = SCDynamicStoreCopyComputerName(sc, &nameEncoding)) != NULL)
    {
      if (CFStringGetCString(nameRef, nameBuffer, sizeof(nameBuffer),
			     kCFStringEncodingUTF8))
      {
        cupsdLogMessage(CUPSD_LOG_DEBUG,
	                "Dynamic store computer name is \"%s\".", nameBuffer);
	cupsdSetString(&DNSSDComputerName, nameBuffer);
      }

      CFRelease(nameRef);
    }

    if (!DNSSDComputerName)
    {
     /*
      * Use the ServerName instead...
      */

      cupsdLogMessage(CUPSD_LOG_DEBUG,
                      "Using ServerName \"%s\" as computer name.", ServerName);
      cupsdSetString(&DNSSDComputerName, ServerName);
    }

    if (!DNSSDHostName)
    {
     /*
      * Get the local hostname from the dynamic store...
      */

      if ((nameRef = SCDynamicStoreCopyLocalHostName(sc)) != NULL)
      {
	if (CFStringGetCString(nameRef, nameBuffer, sizeof(nameBuffer),
			       kCFStringEncodingUTF8))
	{
	  cupsdLogMessage(CUPSD_LOG_DEBUG, "Dynamic store host name is \"%s\".", nameBuffer);

	  if (strchr(nameBuffer, '.'))
	    cupsdSetString(&DNSSDHostName, nameBuffer);
	  else
	    cupsdSetStringf(&DNSSDHostName, "%s.local", nameBuffer);

	  cupsdLogMessage(CUPSD_LOG_INFO, "Defaulting to \"DNSSDHostName %s\".", DNSSDHostName);
	}

	CFRelease(nameRef);
      }
    }

    if (!DNSSDHostName)
    {
     /*
      * Use the ServerName instead...
      */

      cupsdLogMessage(CUPSD_LOG_DEBUG, "Using ServerName \"%s\" as host name.", ServerName);
      cupsdSetString(&DNSSDHostName, ServerName);

      cupsdLogMessage(CUPSD_LOG_INFO, "Defaulting to \"DNSSDHostName %s\".", DNSSDHostName);
    }

   /*
    * Get any Back-to-My-Mac domains and add them as aliases...
    */

    cupsdFreeAliases(DNSSDAlias);
    DNSSDAlias = NULL;

    btmm = SCDynamicStoreCopyValue(sc, CFSTR("Setup:/Network/BackToMyMac"));
    if (btmm && CFGetTypeID(btmm) == CFDictionaryGetTypeID())
    {
      cupsdLogMessage(CUPSD_LOG_DEBUG, "%d Back to My Mac aliases to add.",
		      (int)CFDictionaryGetCount(btmm));
      CFDictionaryApplyFunction(btmm, dnssdAddAlias, NULL);
    }
    else if (btmm)
      cupsdLogMessage(CUPSD_LOG_ERROR,
		      "Bad Back to My Mac data in dynamic store!");
    else
      cupsdLogMessage(CUPSD_LOG_DEBUG, "No Back to My Mac aliases to add.");

    if (btmm)
      CFRelease(btmm);

    CFRelease(sc);
  }
  else
#  endif /* __APPLE__ */
#  ifdef HAVE_AVAHI
  if (DNSSDClient)
  {
    const char	*host_name = avahi_client_get_host_name(DNSSDClient);

    cupsdSetString(&DNSSDComputerName, host_name ? host_name : ServerName);

    if (!DNSSDHostName)
    {
      const char *host_fqdn = avahi_client_get_host_name_fqdn(DNSSDClient);

      if (host_fqdn)
	cupsdSetString(&DNSSDHostName, host_fqdn);
      else if (strchr(ServerName, '.'))
	cupsdSetString(&DNSSDHostName, ServerName);
      else
	cupsdSetStringf(&DNSSDHostName, "%s.local", ServerName);

      cupsdLogMessage(CUPSD_LOG_INFO, "Defaulting to \"DNSSDHostName %s\".", DNSSDHostName);
    }
  }
  else
#  endif /* HAVE_AVAHI */
  {
    cupsdSetString(&DNSSDComputerName, ServerName);

    if (!DNSSDHostName)
    {
      if (strchr(ServerName, '.'))
	cupsdSetString(&DNSSDHostName, ServerName);
      else
	cupsdSetStringf(&DNSSDHostName, "%s.local", ServerName);

      cupsdLogMessage(CUPSD_LOG_INFO, "Defaulting to \"DNSSDHostName %s\".", DNSSDHostName);
    }
  }

 /*
  * Then (re)register the web interface if enabled...
  */

  if (BrowseWebIF)
  {
    if (DNSSDComputerName)
      snprintf(webif, sizeof(webif), "CUPS @ %s", DNSSDComputerName);
    else
      strlcpy(webif, "CUPS", sizeof(webif));

    dnssdDeregisterInstance(&WebIFSrv, from_callback);
    dnssdRegisterInstance(&WebIFSrv, NULL, webif, "_http._tcp", "_printer", DNSSDPort, NULL, 1, from_callback);
  }
}
Beispiel #9
0
int					/* O - Exit status */
main(int  argc,				/* I - Number of command-line arguments */
     char *argv[])			/* I - Command-line arguments */
{
  int		i;			/* Looping var */
  ppd_file_t	*ppd;			/* PPD file loaded from disk */
  int		status;			/* Status of tests (0 = success, 1 = fail) */
  int		conflicts;		/* Number of conflicts */
  char		*s;			/* String */
  char		buffer[8192];		/* String buffer */
  const char	*text,			/* Localized text */
		*val;			/* Option value */
  int		num_options;		/* Number of options */
  cups_option_t	*options;		/* Options */
  ppd_size_t	minsize,		/* Minimum size */
		maxsize,		/* Maximum size */
		*size;			/* Current size */
  ppd_attr_t	*attr;			/* Current attribute */
  _ppd_cache_t	*pc;			/* PPD cache */


  status = 0;

  if (argc == 1)
  {
   /*
    * Setup directories for locale stuff...
    */

    if (access("locale", 0))
    {
      mkdir("locale", 0777);
      mkdir("locale/fr", 0777);
      symlink("../../../locale/cups_fr.po", "locale/fr/cups_fr.po");
      mkdir("locale/zh_TW", 0777);
      symlink("../../../locale/cups_zh_TW.po", "locale/zh_TW/cups_zh_TW.po");
    }

    putenv("LOCALEDIR=locale");
    putenv("SOFTWARE=CUPS");

   /*
    * Do tests with test.ppd...
    */

    fputs("ppdOpenFile(test.ppd): ", stdout);

    if ((ppd = _ppdOpenFile("test.ppd", _PPD_LOCALIZATION_ALL)) != NULL)
      puts("PASS");
    else
    {
      ppd_status_t	err;		/* Last error in file */
      int		line;		/* Line number in file */


      status ++;
      err = ppdLastError(&line);

      printf("FAIL (%s on line %d)\n", ppdErrorString(err), line);
    }

    fputs("ppdFindAttr(wildcard): ", stdout);
    if ((attr = ppdFindAttr(ppd, "cupsTest", NULL)) == NULL)
    {
      status ++;
      puts("FAIL (not found)");
    }
    else if (strcmp(attr->name, "cupsTest") || strcmp(attr->spec, "Foo"))
    {
      status ++;
      printf("FAIL (got \"%s %s\")\n", attr->name, attr->spec);
    }
    else
      puts("PASS");

    fputs("ppdFindNextAttr(wildcard): ", stdout);
    if ((attr = ppdFindNextAttr(ppd, "cupsTest", NULL)) == NULL)
    {
      status ++;
      puts("FAIL (not found)");
    }
    else if (strcmp(attr->name, "cupsTest") || strcmp(attr->spec, "Bar"))
    {
      status ++;
      printf("FAIL (got \"%s %s\")\n", attr->name, attr->spec);
    }
    else
      puts("PASS");

    fputs("ppdFindAttr(Foo): ", stdout);
    if ((attr = ppdFindAttr(ppd, "cupsTest", "Foo")) == NULL)
    {
      status ++;
      puts("FAIL (not found)");
    }
    else if (strcmp(attr->name, "cupsTest") || strcmp(attr->spec, "Foo"))
    {
      status ++;
      printf("FAIL (got \"%s %s\")\n", attr->name, attr->spec);
    }
    else
      puts("PASS");

    fputs("ppdFindNextAttr(Foo): ", stdout);
    if ((attr = ppdFindNextAttr(ppd, "cupsTest", "Foo")) != NULL)
    {
      status ++;
      printf("FAIL (got \"%s %s\")\n", attr->name, attr->spec);
    }
    else
      puts("PASS");

    fputs("ppdMarkDefaults: ", stdout);
    ppdMarkDefaults(ppd);

    if ((conflicts = ppdConflicts(ppd)) == 0)
      puts("PASS");
    else
    {
      status ++;
      printf("FAIL (%d conflicts)\n", conflicts);
    }

    fputs("ppdEmitString (defaults): ", stdout);
    if ((s = ppdEmitString(ppd, PPD_ORDER_ANY, 0.0)) != NULL &&
	!strcmp(s, default_code))
      puts("PASS");
    else
    {
      status ++;
      printf("FAIL (%d bytes instead of %d)\n", s ? (int)strlen(s) : 0,
	     (int)strlen(default_code));

      if (s)
	puts(s);
    }

    if (s)
      free(s);

    fputs("ppdEmitString (custom size and string): ", stdout);
    ppdMarkOption(ppd, "PageSize", "Custom.400x500");
    ppdMarkOption(ppd, "StringOption", "{String1=\"value 1\" String2=value(2)}");

    if ((s = ppdEmitString(ppd, PPD_ORDER_ANY, 0.0)) != NULL &&
	!strcmp(s, custom_code))
      puts("PASS");
    else
    {
      status ++;
      printf("FAIL (%d bytes instead of %d)\n", s ? (int)strlen(s) : 0,
	     (int)strlen(custom_code));

      if (s)
	puts(s);
    }

    if (s)
      free(s);

   /*
    * Test constraints...
    */

    fputs("cupsGetConflicts(InputSlot=Envelope): ", stdout);
    ppdMarkOption(ppd, "PageSize", "Letter");

    num_options = cupsGetConflicts(ppd, "InputSlot", "Envelope", &options);
    if (num_options != 2 ||
        (val = cupsGetOption("PageRegion", num_options, options)) == NULL ||
	_cups_strcasecmp(val, "Letter") ||
	(val = cupsGetOption("PageSize", num_options, options)) == NULL ||
	_cups_strcasecmp(val, "Letter"))
    {
      printf("FAIL (%d options:", num_options);
      for (i = 0; i < num_options; i ++)
        printf(" %s=%s", options[i].name, options[i].value);
      puts(")");
      status ++;
    }
    else
      puts("PASS");

    fputs("ppdConflicts(): ", stdout);
    ppdMarkOption(ppd, "InputSlot", "Envelope");

    if ((conflicts = ppdConflicts(ppd)) == 2)
      puts("PASS (2)");
    else
    {
      printf("FAIL (%d)\n", conflicts);
      status ++;
    }

    fputs("cupsResolveConflicts(InputSlot=Envelope): ", stdout);
    num_options = 0;
    options     = NULL;
    if (!cupsResolveConflicts(ppd, "InputSlot", "Envelope", &num_options,
                             &options))
    {
      puts("FAIL (Unable to resolve)");
      status ++;
    }
    else if (num_options != 2 ||
             !cupsGetOption("PageSize", num_options, options))
    {
      printf("FAIL (%d options:", num_options);
      for (i = 0; i < num_options; i ++)
        printf(" %s=%s", options[i].name, options[i].value);
      puts(")");
      status ++;
    }
    else
      puts("PASS (Resolved by changing PageSize)");

    cupsFreeOptions(num_options, options);

    fputs("cupsResolveConflicts(No option/choice): ", stdout);
    num_options = 0;
    options     = NULL;
    if (cupsResolveConflicts(ppd, NULL, NULL, &num_options, &options) &&
        num_options == 1 && !_cups_strcasecmp(options[0].name, "InputSlot") &&
	!_cups_strcasecmp(options[0].value, "Tray"))
      puts("PASS (Resolved by changing InputSlot)");
    else if (num_options > 0)
    {
      printf("FAIL (%d options:", num_options);
      for (i = 0; i < num_options; i ++)
        printf(" %s=%s", options[i].name, options[i].value);
      puts(")");
      status ++;
    }
    else
    {
      puts("FAIL (Unable to resolve)");
      status ++;
    }
    cupsFreeOptions(num_options, options);

    fputs("ppdInstallableConflict(): ", stdout);
    if (ppdInstallableConflict(ppd, "Duplex", "DuplexNoTumble") &&
        !ppdInstallableConflict(ppd, "Duplex", "None"))
      puts("PASS");
    else if (!ppdInstallableConflict(ppd, "Duplex", "DuplexNoTumble"))
    {
      puts("FAIL (Duplex=DuplexNoTumble did not conflict)");
      status ++;
    }
    else
    {
      puts("FAIL (Duplex=None conflicted)");
      status ++;
    }

   /*
    * ppdPageSizeLimits
    */

    fputs("ppdPageSizeLimits: ", stdout);
    if (ppdPageSizeLimits(ppd, &minsize, &maxsize))
    {
      if (minsize.width != 36 || minsize.length != 36 ||
          maxsize.width != 1080 || maxsize.length != 86400)
      {
        printf("FAIL (got min=%.0fx%.0f, max=%.0fx%.0f, "
	       "expected min=36x36, max=1080x86400)\n", minsize.width,
	       minsize.length, maxsize.width, maxsize.length);
        status ++;
      }
      else
        puts("PASS");
    }
    else
    {
      puts("FAIL (returned 0)");
      status ++;
    }

   /*
    * cupsMarkOptions with PWG and IPP size names.
    */

    fputs("cupsMarkOptions(media=iso-a4): ", stdout);
    num_options = cupsAddOption("media", "iso-a4", 0, &options);
    cupsMarkOptions(ppd, num_options, options);
    cupsFreeOptions(num_options, options);

    size = ppdPageSize(ppd, NULL);
    if (!size || strcmp(size->name, "A4"))
    {
      printf("FAIL (%s)\n", size ? size->name : "unknown");
      status ++;
    }
    else
      puts("PASS");

    fputs("cupsMarkOptions(media=na_letter_8.5x11in): ", stdout);
    num_options = cupsAddOption("media", "na_letter_8.5x11in", 0, &options);
    cupsMarkOptions(ppd, num_options, options);
    cupsFreeOptions(num_options, options);

    size = ppdPageSize(ppd, NULL);
    if (!size || strcmp(size->name, "Letter"))
    {
      printf("FAIL (%s)\n", size ? size->name : "unknown");
      status ++;
    }
    else
      puts("PASS");

    fputs("cupsMarkOptions(media=oe_letter-fullbleed_8.5x11in): ", stdout);
    num_options = cupsAddOption("media", "oe_letter-fullbleed_8.5x11in", 0,
                                &options);
    cupsMarkOptions(ppd, num_options, options);
    cupsFreeOptions(num_options, options);

    size = ppdPageSize(ppd, NULL);
    if (!size || strcmp(size->name, "Letter.Fullbleed"))
    {
      printf("FAIL (%s)\n", size ? size->name : "unknown");
      status ++;
    }
    else
      puts("PASS");

    fputs("cupsMarkOptions(media=A4): ", stdout);
    num_options = cupsAddOption("media", "A4", 0, &options);
    cupsMarkOptions(ppd, num_options, options);
    cupsFreeOptions(num_options, options);

    size = ppdPageSize(ppd, NULL);
    if (!size || strcmp(size->name, "A4"))
    {
      printf("FAIL (%s)\n", size ? size->name : "unknown");
      status ++;
    }
    else
      puts("PASS");

   /*
    * Custom sizes...
    */

    fputs("cupsMarkOptions(media=Custom.8x10in): ", stdout);
    num_options = cupsAddOption("media", "Custom.8x10in", 0, &options);
    cupsMarkOptions(ppd, num_options, options);
    cupsFreeOptions(num_options, options);

    size = ppdPageSize(ppd, NULL);
    if (!size || strcmp(size->name, "Custom") ||
        size->width != 576 || size->length != 720)
    {
      printf("FAIL (%s - %gx%g)\n", size ? size->name : "unknown",
             size ? size->width : 0.0, size ? size->length : 0.0);
      status ++;
    }
    else
      puts("PASS");

   /*
    * Test localization...
    */

    fputs("ppdLocalizeIPPReason(text): ", stdout);
    if (ppdLocalizeIPPReason(ppd, "foo", NULL, buffer, sizeof(buffer)) &&
        !strcmp(buffer, "Foo Reason"))
      puts("PASS");
    else
    {
      status ++;
      printf("FAIL (\"%s\" instead of \"Foo Reason\")\n", buffer);
    }

    fputs("ppdLocalizeIPPReason(http): ", stdout);
    if (ppdLocalizeIPPReason(ppd, "foo", "http", buffer, sizeof(buffer)) &&
        !strcmp(buffer, "http://foo/bar.html"))
      puts("PASS");
    else
    {
      status ++;
      printf("FAIL (\"%s\" instead of \"http://foo/bar.html\")\n", buffer);
    }

    fputs("ppdLocalizeIPPReason(help): ", stdout);
    if (ppdLocalizeIPPReason(ppd, "foo", "help", buffer, sizeof(buffer)) &&
        !strcmp(buffer, "help:anchor='foo'%20bookID=Vendor%20Help"))
      puts("PASS");
    else
    {
      status ++;
      printf("FAIL (\"%s\" instead of \"help:anchor='foo'%%20bookID=Vendor%%20Help\")\n", buffer);
    }

    fputs("ppdLocalizeIPPReason(file): ", stdout);
    if (ppdLocalizeIPPReason(ppd, "foo", "file", buffer, sizeof(buffer)) &&
        !strcmp(buffer, "/help/foo/bar.html"))
      puts("PASS");
    else
    {
      status ++;
      printf("FAIL (\"%s\" instead of \"/help/foo/bar.html\")\n", buffer);
    }

    putenv("LANG=fr");
    putenv("LC_ALL=fr");
    putenv("LC_CTYPE=fr");
    putenv("LC_MESSAGES=fr");

    fputs("ppdLocalizeIPPReason(fr text): ", stdout);
    if (ppdLocalizeIPPReason(ppd, "foo", NULL, buffer, sizeof(buffer)) &&
        !strcmp(buffer, "La Long Foo Reason"))
      puts("PASS");
    else
    {
      status ++;
      printf("FAIL (\"%s\" instead of \"La Long Foo Reason\")\n", buffer);
    }

    putenv("LANG=zh_TW");
    putenv("LC_ALL=zh_TW");
    putenv("LC_CTYPE=zh_TW");
    putenv("LC_MESSAGES=zh_TW");

    fputs("ppdLocalizeIPPReason(zh_TW text): ", stdout);
    if (ppdLocalizeIPPReason(ppd, "foo", NULL, buffer, sizeof(buffer)) &&
        !strcmp(buffer, "Number 1 Foo Reason"))
      puts("PASS");
    else
    {
      status ++;
      printf("FAIL (\"%s\" instead of \"Number 1 Foo Reason\")\n", buffer);
    }

   /*
    * cupsMarkerName localization...
    */

    putenv("LANG=en");
    putenv("LC_ALL=en");
    putenv("LC_CTYPE=en");
    putenv("LC_MESSAGES=en");

    fputs("ppdLocalizeMarkerName(bogus): ", stdout);

    if ((text = ppdLocalizeMarkerName(ppd, "bogus")) != NULL)
    {
      status ++;
      printf("FAIL (\"%s\" instead of NULL)\n", text);
    }
    else
      puts("PASS");

    fputs("ppdLocalizeMarkerName(cyan): ", stdout);

    if ((text = ppdLocalizeMarkerName(ppd, "cyan")) != NULL &&
        !strcmp(text, "Cyan Toner"))
      puts("PASS");
    else
    {
      status ++;
      printf("FAIL (\"%s\" instead of \"Cyan Toner\")\n",
             text ? text : "(null)");
    }

    putenv("LANG=fr");
    putenv("LC_ALL=fr");
    putenv("LC_CTYPE=fr");
    putenv("LC_MESSAGES=fr");

    fputs("ppdLocalizeMarkerName(fr cyan): ", stdout);
    if ((text = ppdLocalizeMarkerName(ppd, "cyan")) != NULL &&
        !strcmp(text, "La Toner Cyan"))
      puts("PASS");
    else
    {
      status ++;
      printf("FAIL (\"%s\" instead of \"La Toner Cyan\")\n",
             text ? text : "(null)");
    }

    putenv("LANG=zh_TW");
    putenv("LC_ALL=zh_TW");
    putenv("LC_CTYPE=zh_TW");
    putenv("LC_MESSAGES=zh_TW");

    fputs("ppdLocalizeMarkerName(zh_TW cyan): ", stdout);
    if ((text = ppdLocalizeMarkerName(ppd, "cyan")) != NULL &&
        !strcmp(text, "Number 1 Cyan Toner"))
      puts("PASS");
    else
    {
      status ++;
      printf("FAIL (\"%s\" instead of \"Number 1 Cyan Toner\")\n",
             text ? text : "(null)");
    }

    ppdClose(ppd);

   /*
    * Test new constraints...
    */

    fputs("ppdOpenFile(test2.ppd): ", stdout);

    if ((ppd = ppdOpenFile("test2.ppd")) != NULL)
      puts("PASS");
    else
    {
      ppd_status_t	err;		/* Last error in file */
      int		line;		/* Line number in file */


      status ++;
      err = ppdLastError(&line);

      printf("FAIL (%s on line %d)\n", ppdErrorString(err), line);
    }

    fputs("ppdMarkDefaults: ", stdout);
    ppdMarkDefaults(ppd);

    if ((conflicts = ppdConflicts(ppd)) == 0)
      puts("PASS");
    else
    {
      status ++;
      printf("FAIL (%d conflicts)\n", conflicts);
    }

    fputs("ppdEmitString (defaults): ", stdout);
    if ((s = ppdEmitString(ppd, PPD_ORDER_ANY, 0.0)) != NULL &&
	!strcmp(s, default2_code))
      puts("PASS");
    else
    {
      status ++;
      printf("FAIL (%d bytes instead of %d)\n", s ? (int)strlen(s) : 0,
	     (int)strlen(default2_code));

      if (s)
	puts(s);
    }

    if (s)
      free(s);

    fputs("ppdConflicts(): ", stdout);
    ppdMarkOption(ppd, "PageSize", "Env10");
    ppdMarkOption(ppd, "InputSlot", "Envelope");
    ppdMarkOption(ppd, "Quality", "Photo");

    if ((conflicts = ppdConflicts(ppd)) == 1)
      puts("PASS (1)");
    else
    {
      printf("FAIL (%d)\n", conflicts);
      status ++;
    }

    fputs("cupsResolveConflicts(Quality=Photo): ", stdout);
    num_options = 0;
    options     = NULL;
    if (cupsResolveConflicts(ppd, "Quality", "Photo", &num_options,
                             &options))
    {
      printf("FAIL (%d options:", num_options);
      for (i = 0; i < num_options; i ++)
        printf(" %s=%s", options[i].name, options[i].value);
      puts(")");
      status ++;
    }
    else
      puts("PASS (Unable to resolve)");
    cupsFreeOptions(num_options, options);

    fputs("cupsResolveConflicts(No option/choice): ", stdout);
    num_options = 0;
    options     = NULL;
    if (cupsResolveConflicts(ppd, NULL, NULL, &num_options, &options) &&
        num_options == 1 && !_cups_strcasecmp(options->name, "Quality") &&
	!_cups_strcasecmp(options->value, "Normal"))
      puts("PASS");
    else if (num_options > 0)
    {
      printf("FAIL (%d options:", num_options);
      for (i = 0; i < num_options; i ++)
        printf(" %s=%s", options[i].name, options[i].value);
      puts(")");
      status ++;
    }
    else
    {
      puts("FAIL (Unable to resolve!)");
      status ++;
    }
    cupsFreeOptions(num_options, options);

    fputs("cupsResolveConflicts(loop test): ", stdout);
    ppdMarkOption(ppd, "PageSize", "A4");
    ppdMarkOption(ppd, "InputSlot", "Tray");
    ppdMarkOption(ppd, "Quality", "Photo");
    num_options = 0;
    options     = NULL;
    if (!cupsResolveConflicts(ppd, NULL, NULL, &num_options, &options))
      puts("PASS");
    else if (num_options > 0)
    {
      printf("FAIL (%d options:", num_options);
      for (i = 0; i < num_options; i ++)
        printf(" %s=%s", options[i].name, options[i].value);
      puts(")");
    }
    else
      puts("FAIL (No conflicts!)");

    fputs("ppdInstallableConflict(): ", stdout);
    if (ppdInstallableConflict(ppd, "Duplex", "DuplexNoTumble") &&
        !ppdInstallableConflict(ppd, "Duplex", "None"))
      puts("PASS");
    else if (!ppdInstallableConflict(ppd, "Duplex", "DuplexNoTumble"))
    {
      puts("FAIL (Duplex=DuplexNoTumble did not conflict)");
      status ++;
    }
    else
    {
      puts("FAIL (Duplex=None conflicted)");
      status ++;
    }

   /*
    * ppdPageSizeLimits
    */

    ppdMarkDefaults(ppd);

    fputs("ppdPageSizeLimits(default): ", stdout);
    if (ppdPageSizeLimits(ppd, &minsize, &maxsize))
    {
      if (minsize.width != 36 || minsize.length != 36 ||
          maxsize.width != 1080 || maxsize.length != 86400)
      {
        printf("FAIL (got min=%.0fx%.0f, max=%.0fx%.0f, "
	       "expected min=36x36, max=1080x86400)\n", minsize.width,
	       minsize.length, maxsize.width, maxsize.length);
        status ++;
      }
      else
        puts("PASS");
    }
    else
    {
      puts("FAIL (returned 0)");
      status ++;
    }

    ppdMarkOption(ppd, "InputSlot", "Manual");

    fputs("ppdPageSizeLimits(InputSlot=Manual): ", stdout);
    if (ppdPageSizeLimits(ppd, &minsize, &maxsize))
    {
      if (minsize.width != 100 || minsize.length != 100 ||
          maxsize.width != 1000 || maxsize.length != 1000)
      {
        printf("FAIL (got min=%.0fx%.0f, max=%.0fx%.0f, "
	       "expected min=100x100, max=1000x1000)\n", minsize.width,
	       minsize.length, maxsize.width, maxsize.length);
        status ++;
      }
      else
        puts("PASS");
    }
    else
    {
      puts("FAIL (returned 0)");
      status ++;
    }

    ppdMarkOption(ppd, "Quality", "Photo");

    fputs("ppdPageSizeLimits(Quality=Photo): ", stdout);
    if (ppdPageSizeLimits(ppd, &minsize, &maxsize))
    {
      if (minsize.width != 200 || minsize.length != 200 ||
          maxsize.width != 1000 || maxsize.length != 1000)
      {
        printf("FAIL (got min=%.0fx%.0f, max=%.0fx%.0f, "
	       "expected min=200x200, max=1000x1000)\n", minsize.width,
	       minsize.length, maxsize.width, maxsize.length);
        status ++;
      }
      else
        puts("PASS");
    }
    else
    {
      puts("FAIL (returned 0)");
      status ++;
    }

    ppdMarkOption(ppd, "InputSlot", "Tray");

    fputs("ppdPageSizeLimits(Quality=Photo): ", stdout);
    if (ppdPageSizeLimits(ppd, &minsize, &maxsize))
    {
      if (minsize.width != 300 || minsize.length != 300 ||
          maxsize.width != 1080 || maxsize.length != 86400)
      {
        printf("FAIL (got min=%.0fx%.0f, max=%.0fx%.0f, "
	       "expected min=300x300, max=1080x86400)\n", minsize.width,
	       minsize.length, maxsize.width, maxsize.length);
        status ++;
      }
      else
        puts("PASS");
    }
    else
    {
      puts("FAIL (returned 0)");
      status ++;
    }
  }
  else
  {
    const char	*filename;		/* PPD filename */
    struct stat	fileinfo;		/* File information */


    if (!strncmp(argv[1], "-d", 2))
    {
      const char *printer;		/* Printer name */

      if (argv[1][2])
	printer = argv[1] + 2;
      else if (argv[2])
	printer = argv[2];
      else
      {
        puts("Usage: ./testppd -d printer");
	return (1);
      }

      filename = cupsGetPPD(printer);

      if (!filename)
      {
        printf("%s: %s\n", printer, cupsLastErrorString());
        return (1);
      }
    }
    else
      filename = argv[1];

    if (lstat(filename, &fileinfo))
    {
      printf("%s: %s\n", filename, strerror(errno));
      return (1);
    }

    if (S_ISLNK(fileinfo.st_mode))
    {
      char	realfile[1024];		/* Real file path */
      ssize_t	realsize;		/* Size of real file path */


      if ((realsize = readlink(filename, realfile, sizeof(realfile) - 1)) < 0)
        strlcpy(realfile, "Unknown", sizeof(realfile));
      else
        realfile[realsize] = '\0';

      if (stat(realfile, &fileinfo))
	printf("%s: symlink to \"%s\", %s\n", filename, realfile,
	       strerror(errno));
      else
	printf("%s: symlink to \"%s\", %ld bytes\n", filename, realfile,
	       (long)fileinfo.st_size);
    }
    else
      printf("%s: regular file, %ld bytes\n", filename, (long)fileinfo.st_size);

    if ((ppd = ppdOpenFile(filename)) == NULL)
    {
      ppd_status_t	err;		/* Last error in file */
      int		line;		/* Line number in file */


      status ++;
      err = ppdLastError(&line);

      printf("%s: %s on line %d\n", argv[1], ppdErrorString(err), line);
    }
    else
    {
      int		j, k;		/* Looping vars */
      ppd_group_t	*group;		/* Option group */
      ppd_option_t	*option;	/* Option */
      ppd_coption_t	*coption;	/* Custom option */
      ppd_cparam_t	*cparam;	/* Custom parameter */
      ppd_const_t	*c;		/* UIConstraints */
      char		lang[255],	/* LANG environment variable */
			lc_all[255],	/* LC_ALL environment variable */
			lc_ctype[255],	/* LC_CTYPE environment variable */
			lc_messages[255];/* LC_MESSAGES environment variable */


      if (argc > 2)
      {
        snprintf(lang, sizeof(lang), "LANG=%s", argv[2]);
	putenv(lang);
        snprintf(lc_all, sizeof(lc_all), "LC_ALL=%s", argv[2]);
	putenv(lc_all);
        snprintf(lc_ctype, sizeof(lc_ctype), "LC_CTYPE=%s", argv[2]);
	putenv(lc_ctype);
        snprintf(lc_messages, sizeof(lc_messages), "LC_MESSAGES=%s", argv[2]);
	putenv(lc_messages);
      }

      ppdLocalize(ppd);
      ppdMarkDefaults(ppd);

      if (argc > 3)
      {
        text = ppdLocalizeIPPReason(ppd, argv[3], NULL, buffer, sizeof(buffer));
	printf("ppdLocalizeIPPReason(%s)=%s\n", argv[3],
	       text ? text : "(null)");
	return (text == NULL);
      }

      for (i = ppd->num_groups, group = ppd->groups;
	   i > 0;
	   i --, group ++)
      {
	printf("%s (%s):\n", group->name, group->text);

	for (j = group->num_options, option = group->options;
	     j > 0;
	     j --, option ++)
	{
	  printf("    %s (%s):\n", option->keyword, option->text);

	  for (k = 0; k < option->num_choices; k ++)
	    printf("        - %s%s (%s)\n",
	           option->choices[k].marked ? "*" : "",
		   option->choices[k].choice, option->choices[k].text);

          if ((coption = ppdFindCustomOption(ppd, option->keyword)) != NULL)
	  {
	    for (cparam = (ppd_cparam_t *)cupsArrayFirst(coption->params);
	         cparam;
		 cparam = (ppd_cparam_t *)cupsArrayNext(coption->params))
            {
	      switch (cparam->type)
	      {
	        case PPD_CUSTOM_CURVE :
		    printf("              %s(%s): PPD_CUSTOM_CURVE (%g to %g)\n",
		           cparam->name, cparam->text,
			   cparam->minimum.custom_curve,
			   cparam->maximum.custom_curve);
		    break;

	        case PPD_CUSTOM_INT :
		    printf("              %s(%s): PPD_CUSTOM_INT (%d to %d)\n",
		           cparam->name, cparam->text,
			   cparam->minimum.custom_int,
			   cparam->maximum.custom_int);
		    break;

	        case PPD_CUSTOM_INVCURVE :
		    printf("              %s(%s): PPD_CUSTOM_INVCURVE (%g to %g)\n",
		           cparam->name, cparam->text,
			   cparam->minimum.custom_invcurve,
			   cparam->maximum.custom_invcurve);
		    break;

	        case PPD_CUSTOM_PASSCODE :
		    printf("              %s(%s): PPD_CUSTOM_PASSCODE (%d to %d)\n",
		           cparam->name, cparam->text,
			   cparam->minimum.custom_passcode,
			   cparam->maximum.custom_passcode);
		    break;

	        case PPD_CUSTOM_PASSWORD :
		    printf("              %s(%s): PPD_CUSTOM_PASSWORD (%d to %d)\n",
		           cparam->name, cparam->text,
			   cparam->minimum.custom_password,
			   cparam->maximum.custom_password);
		    break;

	        case PPD_CUSTOM_POINTS :
		    printf("              %s(%s): PPD_CUSTOM_POINTS (%g to %g)\n",
		           cparam->name, cparam->text,
			   cparam->minimum.custom_points,
			   cparam->maximum.custom_points);
		    break;

	        case PPD_CUSTOM_REAL :
		    printf("              %s(%s): PPD_CUSTOM_REAL (%g to %g)\n",
		           cparam->name, cparam->text,
			   cparam->minimum.custom_real,
			   cparam->maximum.custom_real);
		    break;

	        case PPD_CUSTOM_STRING :
		    printf("              %s(%s): PPD_CUSTOM_STRING (%d to %d)\n",
		           cparam->name, cparam->text,
			   cparam->minimum.custom_string,
			   cparam->maximum.custom_string);
		    break;
	      }
	    }
	  }
	}
      }

      puts("\nSizes:");
      for (i = ppd->num_sizes, size = ppd->sizes; i > 0; i --, size ++)
        printf("    %s = %gx%g, [%g %g %g %g]\n", size->name, size->width,
	       size->length, size->left, size->bottom, size->right, size->top);

      puts("\nConstraints:");

      for (i = ppd->num_consts, c = ppd->consts; i > 0; i --, c ++)
        printf("    *UIConstraints: *%s %s *%s %s\n", c->option1, c->choice1,
	       c->option2, c->choice2);
      if (ppd->num_consts == 0)
        puts("    NO CONSTRAINTS");

      puts("\nFilters:");

      for (i = 0; i < ppd->num_filters; i ++)
        printf("    %s\n", ppd->filters[i]);

      if (ppd->num_filters == 0)
        puts("    NO FILTERS");

      puts("\nAttributes:");

      for (attr = (ppd_attr_t *)cupsArrayFirst(ppd->sorted_attrs);
           attr;
	   attr = (ppd_attr_t *)cupsArrayNext(ppd->sorted_attrs))
        printf("    *%s %s/%s: \"%s\"\n", attr->name, attr->spec,
	       attr->text, attr->value ? attr->value : "");

      puts("\nPPD Cache:");
      if ((pc = _ppdCacheCreateWithPPD(ppd)) == NULL)
        printf("    Unable to create: %s\n", cupsLastErrorString());
      else
      {
        _ppdCacheWriteFile(pc, "t.cache", NULL);
        puts("    Wrote t.cache.");
      }
    }

    if (!strncmp(argv[1], "-d", 2))
      unlink(filename);
  }

#ifdef __APPLE__
  if (getenv("MallocStackLogging") && getenv("MallocStackLoggingNoCompact"))
  {
    char	command[1024];		/* malloc_history command */

    snprintf(command, sizeof(command), "malloc_history %d -all_by_size",
	     getpid());
    fflush(stdout);
    system(command);
  }
#endif /* __APPLE__ */

  ppdClose(ppd);

  return (status);
}
Beispiel #10
0
static void
scan_devices(int ipv4,			/* I - SNMP IPv4 socket */
             int ipv6)			/* I - SNMP IPv6 socket */
{
  int			fd,		/* File descriptor for this address */
			busy;		/* Are we busy processing something? */
  char			*address,	/* Current address */
			*community;	/* Current community */
  fd_set		input;		/* Input set for select() */
  struct timeval	timeout;	/* Timeout for select() */
  time_t		endtime;	/* End time for scan */
  http_addrlist_t	*addrs,		/* List of addresses */
			*addr;		/* Current address */
  snmp_cache_t		*device;	/* Current device */
  char			temp[1024];	/* Temporary address string */


  gettimeofday(&StartTime, NULL);

 /*
  * First send all of the broadcast queries...
  */

  for (address = (char *)cupsArrayFirst(Addresses);
       address;
       address = (char *)cupsArrayNext(Addresses))
  {
    if (!strcmp(address, "@LOCAL"))
      addrs = get_interface_addresses(NULL);
    else if (!strncmp(address, "@IF(", 4))
    {
      char	ifname[255];		/* Interface name */

      strlcpy(ifname, address + 4, sizeof(ifname));
      if (ifname[0])
        ifname[strlen(ifname) - 1] = '\0';

      addrs = get_interface_addresses(ifname);
    }
    else
      addrs = httpAddrGetList(address, AF_UNSPEC, NULL);

    if (!addrs)
    {
      fprintf(stderr, "ERROR: Unable to scan \"%s\"!\n", address);
      continue;
    }

    for (community = (char *)cupsArrayFirst(Communities);
         community;
	 community = (char *)cupsArrayNext(Communities))
    {
      debug_printf("DEBUG: Scanning for devices in \"%s\" via \"%s\"...\n",
        	   community, address);

      for (addr = addrs; addr; addr = addr->next)
      {
#ifdef AF_INET6
        if (httpAddrFamily(&(addr->addr)) == AF_INET6)
	  fd = ipv6;
	else
#endif /* AF_INET6 */
        fd = ipv4;

        debug_printf("DEBUG: Sending get request to %s...\n",
	             httpAddrString(&(addr->addr), temp, sizeof(temp)));

        _cupsSNMPWrite(fd, &(addr->addr), CUPS_SNMP_VERSION_1, community,
	               CUPS_ASN1_GET_REQUEST, DEVICE_TYPE, DeviceTypeOID);
      }
    }

    httpAddrFreeList(addrs);
  }

 /*
  * Then read any responses that come in over the next 3 seconds...
  */

  endtime = time(NULL) + MaxRunTime;

  FD_ZERO(&input);

  while (time(NULL) < endtime)
  {
    timeout.tv_sec  = 2;
    timeout.tv_usec = 0;

    FD_SET(ipv4, &input);
    if (ipv6 >= 0)
      FD_SET(ipv6, &input);

    fd = ipv4 > ipv6 ? ipv4 : ipv6;
    if (select(fd + 1, &input, NULL, NULL, &timeout) < 0)
    {
      fprintf(stderr, "ERROR: %.3f select() for %d/%d failed: %s\n", run_time(),
              ipv4, ipv6, strerror(errno));
      break;
    }

    busy = 0;

    if (FD_ISSET(ipv4, &input))
    {
      read_snmp_response(ipv4);
      busy = 1;
    }

    if (ipv6 >= 0 && FD_ISSET(ipv6, &input))
    {
      read_snmp_response(ipv6);
      busy = 1;
    }

    if (!busy)
    {
     /*
      * List devices with complete information...
      */

      int sent_something = 0;

      for (device = (snmp_cache_t *)cupsArrayFirst(Devices);
           device;
	   device = (snmp_cache_t *)cupsArrayNext(Devices))
        if (!device->sent && device->info && device->make_and_model)
	{
	  if (device->uri)
	    list_device(device);
	  else
	    probe_device(device);

	  device->sent = sent_something = 1;
	}

      if (!sent_something)
        break;
    }
  }

  debug_printf("DEBUG: %.3f Scan complete!\n", run_time());
}
Beispiel #11
0
static int				/* O - 0 on success, 1 on error */
exec_filters(mime_type_t   *srctype,	/* I - Source type */
             cups_array_t  *filters,	/* I - Array of filters to run */
             const char    *infile,	/* I - File to filter */
	     const char    *outfile,	/* I - File to create */
	     const char    *ppdfile,	/* I - PPD file, if any */
	     const char    *printer,	/* I - Printer name */
	     const char    *user,	/* I - Username */
	     const char    *title,	/* I - Job title */
             int           num_options,	/* I - Number of filter options */
	     cups_option_t *options)	/* I - Filter options */
{
  int		i;			/* Looping var */
  const char	*argv[8],		/* Command-line arguments */
		*envp[15],		/* Environment variables */
		*temp;			/* Temporary string */
  char		*optstr,		/* Filter options */
		content_type[1024],	/* CONTENT_TYPE */
		cups_datadir[1024],	/* CUPS_DATADIR */
		cups_fontpath[1024],	/* CUPS_FONTPATH */
		cups_serverbin[1024],	/* CUPS_SERVERBIN */
		cups_serverroot[1024],	/* CUPS_SERVERROOT */
		lang[1024],		/* LANG */
		path[1024],		/* PATH */
		ppd[1024],		/* PPD */
		printer_info[255],	/* PRINTER_INFO env variable */
		printer_location[255],	/* PRINTER_LOCATION env variable */
		printer_name[255],	/* PRINTER env variable */
		rip_max_cache[1024],	/* RIP_MAX_CACHE */
		userenv[1024],		/* USER */
		program[1024];		/* Program to run */
  mime_filter_t	*filter,		/* Current filter */
		*next;			/* Next filter */
  int		current,		/* Current filter */
		filterfds[2][2],	/* Pipes for filters */
		pid,			/* Process ID of filter */
		status,			/* Exit status */
		retval;			/* Return value */
  cups_array_t	*pids;			/* Executed filters array */
  mime_filter_t	key;			/* Search key for filters */
  cups_lang_t	*language;		/* Current language */
  cups_dest_t	*dest;			/* Destination information */


 /*
  * Setup the filter environment and command-line...
  */

  optstr = escape_options(num_options, options);

  snprintf(content_type, sizeof(content_type), "CONTENT_TYPE=%s/%s",
           srctype->super, srctype->type);
  snprintf(cups_datadir, sizeof(cups_datadir), "CUPS_DATADIR=%s", DataDir);
  snprintf(cups_fontpath, sizeof(cups_fontpath), "CUPS_FONTPATH=%s", FontPath);
  snprintf(cups_serverbin, sizeof(cups_serverbin), "CUPS_SERVERBIN=%s",
           ServerBin);
  snprintf(cups_serverroot, sizeof(cups_serverroot), "CUPS_SERVERROOT=%s",
           ServerRoot);
  language = cupsLangDefault();
  snprintf(lang, sizeof(lang), "LANG=%s.UTF8", language->language);
  snprintf(path, sizeof(path), "PATH=%s", Path);
  if (ppdfile)
    snprintf(ppd, sizeof(ppd), "PPD=%s", ppdfile);
  else if ((temp = getenv("PPD")) != NULL)
    snprintf(ppd, sizeof(ppd), "PPD=%s", temp);
  else
#ifdef __APPLE__
  if (!access("/System/Library/Frameworks/ApplicationServices.framework/"
	      "Versions/A/Frameworks/PrintCore.framework/Versions/A/"
	      "Resources/English.lproj/Generic.ppd", 0))
    strlcpy(ppd, "PPD=/System/Library/Frameworks/ApplicationServices.framework/"
                 "Versions/A/Frameworks/PrintCore.framework/Versions/A/"
		 "Resources/English.lproj/Generic.ppd", sizeof(ppd));
  else
    strlcpy(ppd, "PPD=/System/Library/Frameworks/ApplicationServices.framework/"
                 "Versions/A/Frameworks/PrintCore.framework/Versions/A/"
		 "Resources/Generic.ppd", sizeof(ppd));
#else
    snprintf(ppd, sizeof(ppd), "PPD=%s/model/laserjet.ppd", DataDir);
#endif /* __APPLE__ */
  snprintf(rip_max_cache, sizeof(rip_max_cache), "RIP_MAX_CACHE=%s", RIPCache);
  snprintf(userenv, sizeof(userenv), "USER=%s", user);

  if (printer &&
      (dest = cupsGetNamedDest(CUPS_HTTP_DEFAULT, printer, NULL)) != NULL)
  {
    if ((temp = cupsGetOption("printer-info", dest->num_options,
                              dest->options)) != NULL)
      snprintf(printer_info, sizeof(printer_info), "PRINTER_INFO=%s", temp);
    else
      snprintf(printer_info, sizeof(printer_info), "PRINTER_INFO=%s", printer);

    if ((temp = cupsGetOption("printer-location", dest->num_options,
                              dest->options)) != NULL)
      snprintf(printer_location, sizeof(printer_location),
               "PRINTER_LOCATION=%s", temp);
    else
      strlcpy(printer_location, "PRINTER_LOCATION=Unknown",
              sizeof(printer_location));
  }
  else
  {
    snprintf(printer_info, sizeof(printer_info), "PRINTER_INFO=%s",
             printer ? printer : "Unknown");
    strlcpy(printer_location, "PRINTER_LOCATION=Unknown",
            sizeof(printer_location));
  }

  snprintf(printer_name, sizeof(printer_name), "PRINTER=%s",
	   printer ? printer : "Unknown");

  argv[0] = (char *)printer;
  argv[1] = "1";
  argv[2] = user;
  argv[3] = title;
  argv[4] = cupsGetOption("copies", num_options, options);
  argv[5] = optstr;
  argv[6] = infile;
  argv[7] = NULL;

  if (!argv[4])
    argv[4] = "1";

  envp[0]  = "<CFProcessPath>";
  envp[1]  = content_type;
  envp[2]  = cups_datadir;
  envp[3]  = cups_fontpath;
  envp[4]  = cups_serverbin;
  envp[5]  = cups_serverroot;
  envp[6]  = lang;
  envp[7]  = path;
  envp[8]  = ppd;
  envp[9]  = printer_info;
  envp[10] = printer_location;
  envp[11] = printer_name;
  envp[12] = rip_max_cache;
  envp[13] = userenv;
  envp[14] = NULL;

  for (i = 0; argv[i]; i ++)
    fprintf(stderr, "DEBUG: argv[%d]=\"%s\"\n", i, argv[i]);

  for (i = 0; envp[i]; i ++)
    fprintf(stderr, "DEBUG: envp[%d]=\"%s\"\n", i, envp[i]);

 /*
  * Execute all of the filters...
  */

  pids            = cupsArrayNew((cups_array_func_t)compare_pids, NULL);
  current         = 0;
  filterfds[0][0] = -1;
  filterfds[0][1] = -1;
  filterfds[1][0] = -1;
  filterfds[1][1] = -1;

  if (!infile)
    filterfds[0][0] = 0;

  for (filter = (mime_filter_t *)cupsArrayFirst(filters);
       filter;
       filter = next, current = 1 - current)
  {
    next = (mime_filter_t *)cupsArrayNext(filters);

    if (filter->filter[0] == '/')
      strlcpy(program, filter->filter, sizeof(program));
    else
      snprintf(program, sizeof(program), "%s/filter/%s", ServerBin,
	       filter->filter);

    if (filterfds[!current][1] > 1)
    {
      close(filterfds[1 - current][0]);
      close(filterfds[1 - current][1]);

      filterfds[1 - current][0] = -1;
      filterfds[1 - current][0] = -1;
    }

    if (next)
      open_pipe(filterfds[1 - current]);
    else if (outfile)
    {
      filterfds[1 - current][1] = open(outfile, O_CREAT | O_TRUNC | O_WRONLY,
                                       0666);

      if (filterfds[1 - current][1] < 0)
        fprintf(stderr, "ERROR: Unable to create \"%s\" - %s\n", outfile,
	        strerror(errno));
    }
    else
      filterfds[1 - current][1] = 1;

    pid = exec_filter(program, (char **)argv, (char **)envp,
                      filterfds[current][0], filterfds[1 - current][1]);

    if (pid > 0)
    {
      fprintf(stderr, "INFO: %s (PID %d) started.\n", filter->filter, pid);

      filter->cost = pid;
      cupsArrayAdd(pids, filter);
    }
    else
      break;

    argv[6] = NULL;
  }

 /*
  * Close remaining pipes...
  */

  if (filterfds[0][1] > 1)
  {
    close(filterfds[0][0]);
    close(filterfds[0][1]);
  }

  if (filterfds[1][1] > 1)
  {
    close(filterfds[1][0]);
    close(filterfds[1][1]);
  }

 /*
  * Wait for the children to exit...
  */

  retval = 0;

  while (cupsArrayCount(pids) > 0)
  {
    if ((pid = wait(&status)) < 0)
      continue;

    key.cost = pid;
    if ((filter = (mime_filter_t *)cupsArrayFind(pids, &key)) != NULL)
    {
      cupsArrayRemove(pids, filter);

      if (status)
      {
	if (WIFEXITED(status))
	  fprintf(stderr, "ERROR: %s (PID %d) stopped with status %d\n",
		  filter->filter, pid, WEXITSTATUS(status));
	else
	  fprintf(stderr, "ERROR: %s (PID %d) crashed on signal %d\n",
		  filter->filter, pid, WTERMSIG(status));

        retval = 1;
      }
      else
        fprintf(stderr, "INFO: %s (PID %d) exited with no errors.\n",
	        filter->filter, pid);
    }
  }

  cupsArrayDelete(pids);

  return (retval);
}
Beispiel #12
0
int					/* O - Exit status */
main(int  argc,				/* I - Number of command-line args */
     char *argv[])			/* I - Command-line arguments */
{
  int		i;			/* Looping vars */
  const char	*command,		/* Command name */
		*opt,			/* Current option */
		*printer;		/* Printer name */
  mime_type_t	*printer_type,		/* Printer MIME type */
		*prefilter_type;	/* Printer prefilter MIME type */
  char		*srctype,		/* Source type */
		*dsttype,		/* Destination type */
		super[MIME_MAX_SUPER],	/* Super-type name */
		type[MIME_MAX_TYPE];	/* Type name */
  int		compression;		/* Compression of file */
  int		cost;			/* Cost of filters */
  mime_t	*mime;			/* MIME database */
  char		mimedir[1024];		/* MIME directory */
  char		*infile,		/* File to filter */
		*outfile;		/* File to create */
  char		cupsdconf[1024];	/* cupsd.conf file */
  const char	*server_root;		/* CUPS_SERVERROOT environment variable */
  mime_type_t	*src,			/* Source type */
		*dst;			/* Destination type */
  cups_array_t	*filters;		/* Filters for the file */
  int		num_options;		/* Number of options */
  cups_option_t	*options;		/* Options */
  const char	*ppdfile;		/* PPD file */
  const char	*title,			/* Title string */
		*user;			/* Username */
  int		all_filters,		/* Use all filters */
		removeppd,		/* Remove PPD file */
		removeinfile;		/* Remove input file */
  int		status;			/* Execution status */


 /*
  * Setup defaults...
  */

  if ((command = strrchr(argv[0], '/')) != NULL)
    command ++;
  else
    command = argv[0];

  printer      = !strcmp(command, "convert") ? "tofile" : "cupsfilter";
  mime         = NULL;
  srctype      = NULL;
  compression  = 0;
  dsttype      = "application/pdf";
  infile       = NULL;
  outfile      = NULL;
  num_options  = 0;
  options      = NULL;
  ppdfile      = NULL;
  title        = NULL;
  user         = cupsUser();
  all_filters  = 0;
  removeppd    = 0;
  removeinfile = 0;

  if ((server_root = getenv("CUPS_SERVERROOT")) == NULL)
    server_root = CUPS_SERVERROOT;

  snprintf(cupsdconf, sizeof(cupsdconf), "%s/cupsd.conf", server_root);

 /*
  * Process command-line arguments...
  */

  _cupsSetLocale(argv);

  for (i = 1; i < argc; i ++)
    if (argv[i][0] == '-')
    {
      for (opt = argv[i] + 1; *opt; opt ++)
        switch (*opt)
	{
	  case '-' : /* Next argument is a filename... */
	      i ++;
	      if (i < argc && !infile)
	        infile = argv[i];
	      else
	        usage(opt);
	      break;

          case 'a' : /* Specify option... */
	      i ++;
	      if (i < argc)
	        num_options = cupsParseOptions(argv[i], num_options, &options);
	      else
	        usage(opt);
	      break;

          case 'c' : /* Specify cupsd.conf file location... */
	      i ++;
	      if (i < argc)
	      {
	        if (!strcmp(command, "convert"))
		  num_options = cupsAddOption("copies", argv[i], num_options,
					      &options);
		else
		  strlcpy(cupsdconf, argv[i], sizeof(cupsdconf));
	      }
	      else
	        usage(opt);
	      break;

          case 'd' : /* Specify the real printer name */
	      i ++;
	      if (i < argc)
	        printer = argv[i];
	      else
	        usage(opt);
	      break;

	  case 'D' : /* Delete input file after conversion */
	      removeinfile = 1;
	      break;

          case 'e' : /* Use every filter from the PPD file */
	      all_filters = 1;
	      break;

          case 'f' : /* Specify input file... */
	      i ++;
	      if (i < argc && !infile)
	        infile = argv[i];
	      else
	        usage(opt);
	      break;

          case 'i' : /* Specify source MIME type... */
	      i ++;
	      if (i < argc)
	      {
	        if (sscanf(argv[i], "%15[^/]/%255s", super, type) != 2)
		  usage(opt);

                srctype = argv[i];
	      }
	      else
	        usage(opt);
	      break;

          case 'j' : /* Get job file or specify destination MIME type... */
              if (strcmp(command, "convert"))
	      {
	        i ++;
		if (i < argc)
		{
		  get_job_file(argv[i]);
		  infile = TempFile;
		}
		else
		  usage(opt);

                break;
	      }

          case 'm' : /* Specify destination MIME type... */
	      i ++;
	      if (i < argc)
	      {
	        if (sscanf(argv[i], "%15[^/]/%255s", super, type) != 2)
		  usage(opt);

                dsttype = argv[i];
	      }
	      else
	        usage(opt);
	      break;

          case 'n' : /* Specify number of copies... */
	      i ++;
	      if (i < argc)
	        num_options = cupsAddOption("copies", argv[i], num_options,
		                            &options);
	      else
	        usage(opt);
	      break;

          case 'o' : /* Specify option(s) or output filename */
	      i ++;
	      if (i < argc)
	      {
	        if (!strcmp(command, "convert"))
		{
		  if (outfile)
		    usage(NULL);
		  else
		    outfile = argv[i];
		}
		else
	          num_options = cupsParseOptions(argv[i], num_options,
		                                 &options);
	      }
	      else
	        usage(opt);
	      break;

          case 'p' : /* Specify PPD file... */
          case 'P' : /* Specify PPD file... */
	      i ++;
	      if (i < argc)
	        ppdfile = argv[i];
	      else
	        usage(opt);
	      break;

          case 't' : /* Specify title... */
          case 'J' : /* Specify title... */
	      i ++;
	      if (i < argc)
	        title = argv[i];
	      else
	        usage(opt);
	      break;

	  case 'u' : /* Delete PPD file after conversion */
	      removeppd = 1;
	      break;

          case 'U' : /* Specify username... */
	      i ++;
	      if (i < argc)
	        user = argv[i];
	      else
	        usage(opt);
	      break;

	  default : /* Something we don't understand... */
	      usage(opt);
	      break;
	}
    }
    else if (!infile)
    {
      if (strcmp(command, "convert"))
	infile = argv[i];
      else
	usage(NULL);
    }
    else
    {
      _cupsLangPuts(stderr,
                    _("cupsfilter: Only one filename can be specified."));
      usage(NULL);
    }

  if (!infile && !srctype)
    usage(NULL);

  if (!title)
  {
    if (!infile)
      title = "(stdin)";
    else if ((title = strrchr(infile, '/')) != NULL)
      title ++;
    else
      title = infile;
  }

 /*
  * Load the cupsd.conf file and create the MIME database...
  */

  if (read_cupsd_conf(cupsdconf))
    return (1);

  snprintf(mimedir, sizeof(mimedir), "%s/mime", DataDir);

  mime = mimeLoadTypes(NULL, mimedir);
  mime = mimeLoadTypes(mime, ServerRoot);
  mime = mimeLoadFilters(mime, mimedir, Path);
  mime = mimeLoadFilters(mime, ServerRoot, Path);

  if (!mime)
  {
    _cupsLangPrintf(stderr,
                    _("%s: Unable to read MIME database from \"%s\" or "
		      "\"%s\"."),
		    command, mimedir, ServerRoot);
    return (1);
  }

  prefilter_type = NULL;

  if (all_filters)
    printer_type = add_printer_filters(command, mime, printer, ppdfile,
				       &prefilter_type);
  else
    printer_type   = mimeType(mime, "application", "vnd.cups-postscript");

 /*
  * Get the source and destination types...
  */

  if (srctype)
  {
    sscanf(srctype, "%15[^/]/%255s", super, type);
    if ((src = mimeType(mime, super, type)) == NULL)
    {
      _cupsLangPrintf(stderr,
		      _("%s: Unknown source MIME type %s/%s."),
		      command, super, type);
      return (1);
    }
  }
  else if ((src = mimeFileType(mime, infile, infile, &compression)) == NULL)
  {
    _cupsLangPrintf(stderr,
                    _("%s: Unable to determine MIME type of \"%s\"."),
		    command, infile);
    return (1);
  }

  sscanf(dsttype, "%15[^/]/%255s", super, type);
  if (!_cups_strcasecmp(super, "printer"))
    dst = printer_type;
  else if ((dst = mimeType(mime, super, type)) == NULL)
  {
    _cupsLangPrintf(stderr,
                    _("%s: Unknown destination MIME type %s/%s."),
		    command, super, type);
    return (1);
  }

 /*
  * Figure out how to filter the file...
  */

  if (src == dst)
  {
   /*
    * Special case - no filtering needed...
    */

    filters = cupsArrayNew(NULL, NULL);
    cupsArrayAdd(filters, &GZIPFilter);
    GZIPFilter.src = src;
    GZIPFilter.dst = dst;
  }
  else if ((filters = mimeFilter(mime, src, dst, &cost)) == NULL)
  {
    _cupsLangPrintf(stderr,
                    _("%s: No filter to convert from %s/%s to %s/%s."),
		    command, src->super, src->type, dst->super, dst->type);
    return (1);
  }
  else if (compression)
    cupsArrayInsert(filters, &GZIPFilter);

  if (prefilter_type)
  {
   /*
    * Add pre-filters...
    */

    mime_filter_t	*filter,	/* Current filter */
			*prefilter;	/* Current pre-filter */
    cups_array_t	*prefilters = cupsArrayNew(NULL, NULL);
					/* New filters array */


    for (filter = (mime_filter_t *)cupsArrayFirst(filters);
	 filter;
	 filter = (mime_filter_t *)cupsArrayNext(filters))
    {
      if ((prefilter = mimeFilterLookup(mime, filter->src,
                                        prefilter_type)) != NULL)
	cupsArrayAdd(prefilters, prefilter);

      cupsArrayAdd(prefilters, filter);
    }

    cupsArrayDelete(filters);
    filters = prefilters;
  }

 /*
  * Do it!
  */

  status = exec_filters(src, filters, infile, outfile, ppdfile, printer, user,
                        title, num_options, options);

 /*
  * Remove files as needed, then exit...
  */

  if (TempFile[0])
    unlink(TempFile);

  if (removeppd && ppdfile)
    unlink(ppdfile);

  if (removeinfile && infile)
    unlink(infile);

  return (status);
}
Beispiel #13
0
static void
ppd_mark_option(ppd_file_t *ppd,	/* I - PPD file */
                const char *option,	/* I - Option name */
                const char *choice)	/* I - Choice name */
{
  int		i, j;			/* Looping vars */
  ppd_option_t	*o;			/* Option pointer */
  ppd_choice_t	*c,			/* Choice pointer */
		*oldc,			/* Old choice pointer */
		key;			/* Search key for choice */
  struct lconv	*loc;			/* Locale data */


  DEBUG_printf(("7ppd_mark_option(ppd=%p, option=\"%s\", choice=\"%s\")",
        	ppd, option, choice));

 /*
  * AP_D_InputSlot is the "default input slot" on MacOS X, and setting
  * it clears the regular InputSlot choices...
  */

  if (!_cups_strcasecmp(option, "AP_D_InputSlot"))
  {
    cupsArraySave(ppd->options);

    if ((o = ppdFindOption(ppd, "InputSlot")) != NULL)
    {
      key.option = o;
      if ((oldc = (ppd_choice_t *)cupsArrayFind(ppd->marked, &key)) != NULL)
      {
        oldc->marked = 0;
        cupsArrayRemove(ppd->marked, oldc);
      }
    }

    cupsArrayRestore(ppd->options);
  }

 /*
  * Check for custom options...
  */

  cupsArraySave(ppd->options);

  o = ppdFindOption(ppd, option);

  cupsArrayRestore(ppd->options);

  if (!o)
    return;

  //loc = localeconv();

  if (!_cups_strncasecmp(choice, "Custom.", 7))
  {
   /*
    * Handle a custom option...
    */

    if ((c = ppdFindChoice(o, "Custom")) == NULL)
      return;

    if (!_cups_strcasecmp(option, "PageSize"))
    {
     /*
      * Handle custom page sizes...
      */

      ppdPageSize(ppd, choice);
    }
    else
    {
     /*
      * Handle other custom options...
      */

      ppd_coption_t	*coption;	/* Custom option */
      ppd_cparam_t	*cparam;	/* Custom parameter */
      char		*units;		/* Custom points units */


      if ((coption = ppdFindCustomOption(ppd, option)) != NULL)
      {
        if ((cparam = (ppd_cparam_t *)cupsArrayFirst(coption->params)) == NULL)
	  return;

        switch (cparam->type)
	{
	  case PPD_CUSTOM_CURVE :
	  case PPD_CUSTOM_INVCURVE :
	  case PPD_CUSTOM_REAL :
	      cparam->current.custom_real = (float)_cupsStrScand(choice + 7,
	                                                         NULL, loc);
	      break;

	  case PPD_CUSTOM_POINTS :
	      cparam->current.custom_points = (float)_cupsStrScand(choice + 7,
	                                                           &units,
	                                                           loc);

              if (units)
	      {
        	if (!_cups_strcasecmp(units, "cm"))
	          cparam->current.custom_points *= 72.0f / 2.54f;
        	else if (!_cups_strcasecmp(units, "mm"))
	          cparam->current.custom_points *= 72.0f / 25.4f;
        	else if (!_cups_strcasecmp(units, "m"))
	          cparam->current.custom_points *= 72.0f / 0.0254f;
        	else if (!_cups_strcasecmp(units, "in"))
	          cparam->current.custom_points *= 72.0f;
        	else if (!_cups_strcasecmp(units, "ft"))
	          cparam->current.custom_points *= 12.0f * 72.0f;
              }
	      break;

	  case PPD_CUSTOM_INT :
	      cparam->current.custom_int = atoi(choice + 7);
	      break;

	  case PPD_CUSTOM_PASSCODE :
	  case PPD_CUSTOM_PASSWORD :
	  case PPD_CUSTOM_STRING :
	      if (cparam->current.custom_string)
	        _cupsStrFree(cparam->current.custom_string);

	      cparam->current.custom_string = _cupsStrAlloc(choice + 7);
	      break;
	}
      }
    }

   /*
    * Make sure that we keep the option marked below...
    */

    choice = "Custom";
  }
  else if (choice[0] == '{')
  {
   /*
    * Handle multi-value custom options...
    */

    ppd_coption_t	*coption;	/* Custom option */
    ppd_cparam_t	*cparam;	/* Custom parameter */
    char		*units;		/* Custom points units */
    int			num_vals;	/* Number of values */
    cups_option_t	*vals,		/* Values */
			*val;		/* Value */


    if ((c = ppdFindChoice(o, "Custom")) == NULL)
      return;

    if ((coption = ppdFindCustomOption(ppd, option)) != NULL)
    {
      num_vals = cupsParseOptions(choice, 0, &vals);

      for (i = 0, val = vals; i < num_vals; i ++, val ++)
      {
        if ((cparam = ppdFindCustomParam(coption, val->name)) == NULL)
	  continue;

	switch (cparam->type)
	{
	  case PPD_CUSTOM_CURVE :
	  case PPD_CUSTOM_INVCURVE :
	  case PPD_CUSTOM_REAL :
	      cparam->current.custom_real = (float)_cupsStrScand(val->value,
	                                                         NULL, loc);
	      break;

	  case PPD_CUSTOM_POINTS :
	      cparam->current.custom_points = (float)_cupsStrScand(val->value,
	                                                           &units,
	                                                           loc);

	      if (units)
	      {
        	if (!_cups_strcasecmp(units, "cm"))
		  cparam->current.custom_points *= 72.0f / 2.54f;
        	else if (!_cups_strcasecmp(units, "mm"))
		  cparam->current.custom_points *= 72.0f / 25.4f;
        	else if (!_cups_strcasecmp(units, "m"))
		  cparam->current.custom_points *= 72.0f / 0.0254f;
        	else if (!_cups_strcasecmp(units, "in"))
		  cparam->current.custom_points *= 72.0f;
        	else if (!_cups_strcasecmp(units, "ft"))
		  cparam->current.custom_points *= 12.0f * 72.0f;
	      }
	      break;

	  case PPD_CUSTOM_INT :
	      cparam->current.custom_int = atoi(val->value);
	      break;

	  case PPD_CUSTOM_PASSCODE :
	  case PPD_CUSTOM_PASSWORD :
	  case PPD_CUSTOM_STRING :
	      if (cparam->current.custom_string)
		_cupsStrFree(cparam->current.custom_string);

	      cparam->current.custom_string = _cupsStrRetain(val->value);
	      break;
	}
      }

      cupsFreeOptions(num_vals, vals);
    }
  }
  else
  {
    for (i = o->num_choices, c = o->choices; i > 0; i --, c ++)
      if (!_cups_strcasecmp(c->choice, choice))
        break;

    if (!i)
      return;
  }

 /*
  * Option found; mark it and then handle unmarking any other options.
  */

  if (o->ui != PPD_UI_PICKMANY)
  {
   /*
    * Unmark all other choices...
    */

    if ((oldc = (ppd_choice_t *)cupsArrayFind(ppd->marked, c)) != NULL)
    {
      oldc->marked = 0;
      cupsArrayRemove(ppd->marked, oldc);
    }

    if (!_cups_strcasecmp(option, "PageSize") || !_cups_strcasecmp(option, "PageRegion"))
    {
     /*
      * Mark current page size...
      */

      for (j = 0; j < ppd->num_sizes; j ++)
	ppd->sizes[j].marked = !_cups_strcasecmp(ppd->sizes[j].name,
		                           choice);

     /*
      * Unmark the current PageSize or PageRegion setting, as
      * appropriate...
      */

      cupsArraySave(ppd->options);

      if (!_cups_strcasecmp(option, "PageSize"))
      {
	if ((o = ppdFindOption(ppd, "PageRegion")) != NULL)
        {
          key.option = o;
          if ((oldc = (ppd_choice_t *)cupsArrayFind(ppd->marked, &key)) != NULL)
          {
            oldc->marked = 0;
            cupsArrayRemove(ppd->marked, oldc);
          }
        }
      }
      else
      {
	if ((o = ppdFindOption(ppd, "PageSize")) != NULL)
        {
          key.option = o;
          if ((oldc = (ppd_choice_t *)cupsArrayFind(ppd->marked, &key)) != NULL)
          {
            oldc->marked = 0;
            cupsArrayRemove(ppd->marked, oldc);
          }
        }
      }

      cupsArrayRestore(ppd->options);
    }
    else if (!_cups_strcasecmp(option, "InputSlot"))
    {
     /*
      * Unmark ManualFeed option...
      */

      cupsArraySave(ppd->options);

      if ((o = ppdFindOption(ppd, "ManualFeed")) != NULL)
      {
        key.option = o;
        if ((oldc = (ppd_choice_t *)cupsArrayFind(ppd->marked, &key)) != NULL)
        {
          oldc->marked = 0;
          cupsArrayRemove(ppd->marked, oldc);
        }
      }

      cupsArrayRestore(ppd->options);
    }
    else if (!_cups_strcasecmp(option, "ManualFeed") &&
	     !_cups_strcasecmp(choice, "True"))
    {
     /*
      * Unmark InputSlot option...
      */

      cupsArraySave(ppd->options);

      if ((o = ppdFindOption(ppd, "InputSlot")) != NULL)
      {
        key.option = o;
        if ((oldc = (ppd_choice_t *)cupsArrayFind(ppd->marked, &key)) != NULL)
        {
          oldc->marked = 0;
          cupsArrayRemove(ppd->marked, oldc);
        }
      }

      cupsArrayRestore(ppd->options);
    }
  }

  c->marked = 1;

  cupsArrayAdd(ppd->marked, c);
}
cupsd_subscription_t *			/* O - New subscription object */
cupsdAddSubscription(
    unsigned        mask,		/* I - Event mask */
    cupsd_printer_t *dest,		/* I - Printer, if any */
    cupsd_job_t     *job,		/* I - Job, if any */
    const char      *uri,		/* I - notify-recipient-uri, if any */
    int             sub_id)		/* I - notify-subscription-id or 0 */
{
  cupsd_subscription_t	*temp;		/* New subscription object */


  cupsdLogMessage(CUPSD_LOG_DEBUG,
                  "cupsdAddSubscription(mask=%x, dest=%p(%s), job=%p(%d), "
		  "uri=\"%s\")",
                  mask, dest, dest ? dest->name : "", job, job ? job->id : 0,
		  uri ? uri : "(null)");

  if (!Subscriptions)
    Subscriptions = cupsArrayNew((cups_array_func_t)cupsd_compare_subscriptions,
                                 NULL);

  if (!Subscriptions)
  {
    cupsdLogMessage(CUPSD_LOG_CRIT,
                    "Unable to allocate memory for subscriptions - %s",
        	    strerror(errno));
    return (NULL);
  }

 /*
  * Limit the number of subscriptions...
  */

  if (MaxSubscriptions > 0 && cupsArrayCount(Subscriptions) >= MaxSubscriptions)
  {
    cupsdLogMessage(CUPSD_LOG_DEBUG,
                    "cupsdAddSubscription: Reached MaxSubscriptions %d "
		    "(count=%d)", MaxSubscriptions,
		    cupsArrayCount(Subscriptions));
    return (NULL);
  }

  if (MaxSubscriptionsPerJob > 0 && job)
  {
    int	count;				/* Number of job subscriptions */

    for (temp = (cupsd_subscription_t *)cupsArrayFirst(Subscriptions),
             count = 0;
         temp;
	 temp = (cupsd_subscription_t *)cupsArrayNext(Subscriptions))
      if (temp->job == job)
        count ++;

    if (count >= MaxSubscriptionsPerJob)
    {
      cupsdLogMessage(CUPSD_LOG_DEBUG,
		      "cupsdAddSubscription: Reached MaxSubscriptionsPerJob %d "
		      "for job #%d (count=%d)", MaxSubscriptionsPerJob,
		      job->id, count);
      return (NULL);
    }
  }

  if (MaxSubscriptionsPerPrinter > 0 && dest)
  {
    int	count;				/* Number of printer subscriptions */

    for (temp = (cupsd_subscription_t *)cupsArrayFirst(Subscriptions),
             count = 0;
         temp;
	 temp = (cupsd_subscription_t *)cupsArrayNext(Subscriptions))
      if (temp->dest == dest)
        count ++;

    if (count >= MaxSubscriptionsPerPrinter)
    {
      cupsdLogMessage(CUPSD_LOG_DEBUG,
		      "cupsdAddSubscription: Reached "
		      "MaxSubscriptionsPerPrinter %d for %s (count=%d)",
		      MaxSubscriptionsPerPrinter, dest->name, count);
      return (NULL);
    }
  }

 /*
  * Allocate memory for this subscription...
  */

  if ((temp = calloc(1, sizeof(cupsd_subscription_t))) == NULL)
  {
    cupsdLogMessage(CUPSD_LOG_CRIT,
                    "Unable to allocate memory for subscription object - %s",
                    strerror(errno));
    return (NULL);
  }

 /*
  * Fill in common data...
  */

  if (sub_id)
  {
    temp->id = sub_id;

    if (sub_id >= NextSubscriptionId)
      NextSubscriptionId = sub_id + 1;
  }
  else
  {
    temp->id = NextSubscriptionId;

    NextSubscriptionId ++;
  }

  temp->mask           = mask;
  temp->dest           = dest;
  temp->job            = job;
  temp->pipe           = -1;
  temp->first_event_id = 1;
  temp->next_event_id  = 1;

  cupsdSetString(&(temp->recipient), uri);

 /*
  * Add the subscription to the array...
  */

  cupsArrayAdd(Subscriptions, temp);

 /*
  * For RSS subscriptions, run the notifier immediately...
  */

  if (uri && !strncmp(uri, "rss:", 4))
    cupsd_start_notifier(temp);

  return (temp);
}
Beispiel #15
0
cupsd_quota_t *				/* O - Quota data */
cupsdUpdateQuota(
    cupsd_printer_t *p,			/* I - Printer */
    const char      *username,		/* I - User */
    int             pages,		/* I - Number of pages */
    int             k)			/* I - Number of kilobytes */
{
  cupsd_quota_t		*q;		/* Quota data */
  cupsd_job_t		*job;		/* Current job */
  time_t		curtime;	/* Current time */
  ipp_attribute_t	*attr;		/* Job attribute */


  if (!p || !username)
    return (NULL);

  if (!p->k_limit && !p->page_limit)
    return (NULL);

  if ((q = cupsdFindQuota(p, username)) == NULL)
    return (NULL);

  cupsdLogMessage(CUPSD_LOG_DEBUG,
                  "cupsdUpdateQuota: p=%s username=%s pages=%d k=%d",
                  p->name, username, pages, k);

  curtime = time(NULL);

  if (curtime < q->next_update)
  {
    q->page_count += pages;
    q->k_count    += k;

    return (q);
  }

  if (p->quota_period)
    curtime -= p->quota_period;
  else
    curtime = 0;

  q->next_update = 0;
  q->page_count  = 0;
  q->k_count     = 0;

  for (job = (cupsd_job_t *)cupsArrayFirst(Jobs);
       job;
       job = (cupsd_job_t *)cupsArrayNext(Jobs))
  {
   /*
    * We only care about the current printer/class and user...
    */

    if (_cups_strcasecmp(job->dest, p->name) != 0 ||
        _cups_strcasecmp(job->username, q->username) != 0)
      continue;

   /*
    * Make sure attributes are loaded; we always call cupsdLoadJob() to ensure
    * the access_time member is updated so the job isn't unloaded right away...
    */

    if (!cupsdLoadJob(job))
      continue;

    if ((attr = ippFindAttribute(job->attrs, "time-at-completion",
                                 IPP_TAG_INTEGER)) == NULL)
      if ((attr = ippFindAttribute(job->attrs, "time-at-processing",
                                   IPP_TAG_INTEGER)) == NULL)
        attr = ippFindAttribute(job->attrs, "time-at-creation",
                                IPP_TAG_INTEGER);

    if (attr->values[0].integer < curtime)
    {
     /*
      * This job is too old to count towards the quota, ignore it...
      */

      if (JobAutoPurge && !job->printer && job->state_value > IPP_JOB_STOPPED)
        cupsdDeleteJob(job, CUPSD_JOB_PURGE);

      continue;
    }

    if (q->next_update == 0)
      q->next_update = attr->values[0].integer + p->quota_period;

    if ((attr = ippFindAttribute(job->attrs, "job-media-sheets-completed",
                                 IPP_TAG_INTEGER)) != NULL)
      q->page_count += attr->values[0].integer;

    if ((attr = ippFindAttribute(job->attrs, "job-k-octets",
                                 IPP_TAG_INTEGER)) != NULL)
      q->k_count += attr->values[0].integer;
  }

  return (q);
}
void
cupsdAddEvent(
    cupsd_eventmask_t event,		/* I - Event */
    cupsd_printer_t   *dest,		/* I - Printer associated with event */
    cupsd_job_t       *job,		/* I - Job associated with event */
    const char        *text,		/* I - Notification text */
    ...)				/* I - Additional arguments as needed */
{
  va_list		ap;		/* Pointer to additional arguments */
  char			ftext[1024];	/* Formatted text buffer */
  ipp_attribute_t	*attr;		/* Printer/job attribute */
  cupsd_event_t		*temp;		/* New event pointer */
  cupsd_subscription_t	*sub;		/* Current subscription */


  cupsdLogMessage(CUPSD_LOG_DEBUG2,
                  "cupsdAddEvent(event=%s, dest=%p(%s), job=%p(%d), text=\"%s\", ...)",
		  cupsdEventName(event), dest, dest ? dest->name : "",
		  job, job ? job->id : 0, text);

 /*
  * Keep track of events with any OS-supplied notification mechanisms...
  */

  LastEvent |= event;

#ifdef HAVE_DBUS
  cupsd_send_dbus(event, dest, job);
#endif /* HAVE_DBUS */

 /*
  * Return if we aren't keeping events...
  */

  if (MaxEvents <= 0)
  {
    cupsdLogMessage(CUPSD_LOG_WARN,
                    "cupsdAddEvent: Discarding %s event since MaxEvents is %d!",
                    cupsdEventName(event), MaxEvents);
    return;
  }

 /*
  * Then loop through the subscriptions and add the event to the corresponding
  * caches...
  */

  for (temp = NULL, sub = (cupsd_subscription_t *)cupsArrayFirst(Subscriptions);
       sub;
       sub = (cupsd_subscription_t *)cupsArrayNext(Subscriptions))
  {
   /*
    * Check if this subscription requires this event...
    */

    if ((sub->mask & event) != 0 &&
        (sub->dest == dest || !sub->dest) &&
	(sub->job == job || !sub->job))
    {
     /*
      * Need this event, so create a new event record...
      */

      if ((temp = (cupsd_event_t *)calloc(1, sizeof(cupsd_event_t))) == NULL)
      {
	cupsdLogMessage(CUPSD_LOG_CRIT,
	                "Unable to allocate memory for event - %s",
        	        strerror(errno));
	return;
      }

      temp->event = event;
      temp->time  = time(NULL);
      temp->attrs = ippNew();
      temp->job   = job;

      if (dest)
        temp->dest = dest;
      else if (job)
        temp->dest = dest = cupsdFindPrinter(job->dest);

     /*
      * Add common event notification attributes...
      */

      ippAddString(temp->attrs, IPP_TAG_EVENT_NOTIFICATION, IPP_TAG_CHARSET,
                   "notify-charset", NULL, "utf-8");

      ippAddString(temp->attrs, IPP_TAG_EVENT_NOTIFICATION, IPP_TAG_LANGUAGE,
                   "notify-natural-language", NULL, "en-US");

      ippAddInteger(temp->attrs, IPP_TAG_EVENT_NOTIFICATION, IPP_TAG_INTEGER,
	            "notify-subscription-id", sub->id);

      ippAddInteger(temp->attrs, IPP_TAG_EVENT_NOTIFICATION, IPP_TAG_INTEGER,
	            "notify-sequence-number", sub->next_event_id);

      ippAddString(temp->attrs, IPP_TAG_EVENT_NOTIFICATION, IPP_TAG_KEYWORD,
	           "notify-subscribed-event", NULL, cupsdEventName(event));

      if (sub->user_data_len > 0)
        ippAddOctetString(temp->attrs, IPP_TAG_EVENT_NOTIFICATION,
	                  "notify-user-data", sub->user_data,
			  sub->user_data_len);

      ippAddInteger(temp->attrs, IPP_TAG_EVENT_NOTIFICATION, IPP_TAG_INTEGER,
	            "printer-up-time", time(NULL));

      va_start(ap, text);
      vsnprintf(ftext, sizeof(ftext), text, ap);
      va_end(ap);

      ippAddString(temp->attrs, IPP_TAG_EVENT_NOTIFICATION, IPP_TAG_TEXT,
	           "notify-text", NULL, ftext);

      if (dest)
      {
       /*
	* Add printer attributes...
	*/

	ippAddString(temp->attrs, IPP_TAG_EVENT_NOTIFICATION, IPP_TAG_URI,
	             "notify-printer-uri", NULL, dest->uri);

	ippAddString(temp->attrs, IPP_TAG_EVENT_NOTIFICATION, IPP_TAG_NAME,
	             "printer-name", NULL, dest->name);

	ippAddInteger(temp->attrs, IPP_TAG_EVENT_NOTIFICATION, IPP_TAG_ENUM,
	              "printer-state", dest->state);

	if (dest->num_reasons == 0)
	  ippAddString(temp->attrs, IPP_TAG_EVENT_NOTIFICATION,
	               IPP_TAG_KEYWORD, "printer-state-reasons", NULL,
		       dest->state == IPP_PRINTER_STOPPED ? "paused" : "none");
	else
	  ippAddStrings(temp->attrs, IPP_TAG_EVENT_NOTIFICATION,
	                IPP_TAG_KEYWORD, "printer-state-reasons",
			dest->num_reasons, NULL,
			(const char * const *)dest->reasons);

	ippAddBoolean(temp->attrs, IPP_TAG_EVENT_NOTIFICATION,
	              "printer-is-accepting-jobs", dest->accepting);
      }

      if (job)
      {
       /*
	* Add job attributes...
	*/

	ippAddInteger(temp->attrs, IPP_TAG_EVENT_NOTIFICATION, IPP_TAG_INTEGER,
	              "notify-job-id", job->id);
	ippAddInteger(temp->attrs, IPP_TAG_EVENT_NOTIFICATION, IPP_TAG_ENUM,
	              "job-state", job->state_value);

        if ((attr = ippFindAttribute(job->attrs, "job-name",
	                             IPP_TAG_NAME)) != NULL)
	  ippAddString(temp->attrs, IPP_TAG_EVENT_NOTIFICATION, IPP_TAG_NAME,
	               "job-name", NULL, attr->values[0].string.text);

	switch (job->state_value)
	{
	  case IPP_JOB_PENDING :
              if (dest && dest->state == IPP_PRINTER_STOPPED)
        	ippAddString(temp->attrs, IPP_TAG_EVENT_NOTIFICATION,
		             IPP_TAG_KEYWORD, "job-state-reasons", NULL,
			     "printer-stopped");
              else
        	ippAddString(temp->attrs, IPP_TAG_EVENT_NOTIFICATION,
		             IPP_TAG_KEYWORD, "job-state-reasons", NULL,
			     "none");
              break;

	  case IPP_JOB_HELD :
              if (ippFindAttribute(job->attrs, "job-hold-until", IPP_TAG_KEYWORD) != NULL ||
		  ippFindAttribute(job->attrs, "job-hold-until", IPP_TAG_NAME) != NULL)
        	ippAddString(temp->attrs, IPP_TAG_EVENT_NOTIFICATION,
		             IPP_TAG_KEYWORD, "job-state-reasons", NULL,
			     "job-hold-until-specified");
              else
        	ippAddString(temp->attrs, IPP_TAG_EVENT_NOTIFICATION,
		             IPP_TAG_KEYWORD, "job-state-reasons", NULL,
			     "job-incoming");
              break;

	  case IPP_JOB_PROCESSING :
              ippAddString(temp->attrs, IPP_TAG_EVENT_NOTIFICATION,
		           IPP_TAG_KEYWORD, "job-state-reasons", NULL,
			   "job-printing");
              break;

	  case IPP_JOB_STOPPED :
              ippAddString(temp->attrs, IPP_TAG_EVENT_NOTIFICATION,
		           IPP_TAG_KEYWORD, "job-state-reasons", NULL,
			   "job-stopped");
              break;

	  case IPP_JOB_CANCELED :
              ippAddString(temp->attrs, IPP_TAG_EVENT_NOTIFICATION,
		           IPP_TAG_KEYWORD, "job-state-reasons", NULL,
			   "job-canceled-by-user");
              break;

	  case IPP_JOB_ABORTED :
              ippAddString(temp->attrs, IPP_TAG_EVENT_NOTIFICATION,
		           IPP_TAG_KEYWORD, "job-state-reasons", NULL,
			   "aborted-by-system");
              break;

	  case IPP_JOB_COMPLETED :
              ippAddString(temp->attrs, IPP_TAG_EVENT_NOTIFICATION,
		           IPP_TAG_KEYWORD, "job-state-reasons", NULL,
			   "job-completed-successfully");
              break;
	}

	ippAddInteger(temp->attrs, IPP_TAG_EVENT_NOTIFICATION, IPP_TAG_INTEGER,
	              "job-impressions-completed",
		      job->sheets ? job->sheets->values[0].integer : 0);
      }

     /*
      * Send the notification for this subscription...
      */

      cupsd_send_notification(sub, temp);
    }
  }

  if (temp)
    cupsdMarkDirty(CUPSD_DIRTY_SUBSCRIPTIONS);
  else
    cupsdLogMessage(CUPSD_LOG_DEBUG, "Discarding unused %s event...",
                    cupsdEventName(event));
}
Beispiel #17
0
static void
mime_load_convs(
    mime_t       *mime,			/* I - MIME database */
    const char   *filename,		/* I - Convs file to load */
    const char   *filterpath,		/* I - Path for filters */
    cups_array_t *filtercache)		/* I - Filter program cache */
{
  cups_file_t	*fp;			/* Convs file */
  char		line[1024],		/* Input line from file */
		*lineptr,		/* Current position in line */
		super[MIME_MAX_SUPER],	/* Super-type name */
		type[MIME_MAX_TYPE],	/* Type name */
		*temp,			/* Temporary pointer */
		*filter;		/* Filter program */
  mime_type_t	*temptype,		/* MIME type looping var */
		*dsttype;		/* Destination MIME type */
  int		cost;			/* Cost of filter */


  DEBUG_printf(("2mime_load_convs(mime=%p, filename=\"%s\", filterpath=\"%s\", "
                "filtercache=%p)", mime, filename, filterpath, filtercache));

 /*
  * First try to open the file...
  */

  if ((fp = cupsFileOpen(filename, "r")) == NULL)
  {
    DEBUG_printf(("3mime_load_convs: Unable to open \"%s\": %s", filename,
                  strerror(errno)));
    _mimeError(mime, "Unable to open \"%s\": %s", filename, strerror(errno));
    return;
  }

 /*
  * Then read each line from the file, skipping any comments in the file...
  */

  while (cupsFileGets(fp, line, sizeof(line)) != NULL)
  {
   /*
    * Skip blank lines and lines starting with a #...
    */

    if (!line[0] || line[0] == '#')
      continue;

   /*
    * Strip trailing whitespace...
    */

    for (lineptr = line + strlen(line) - 1;
         lineptr >= line && isspace(*lineptr & 255);
	 lineptr --)
      *lineptr = '\0';

   /*
    * Extract the destination super-type and type names from the middle of
    * the line.
    */

    lineptr = line;
    while (*lineptr != ' ' && *lineptr != '\t' && *lineptr != '\0')
      lineptr ++;

    while (*lineptr == ' ' || *lineptr == '\t')
      lineptr ++;

    temp = super;

    while (*lineptr != '/' && *lineptr != '\n' && *lineptr != '\0' &&
           (temp - super + 1) < MIME_MAX_SUPER)
      *temp++ = (char)tolower(*lineptr++ & 255);

    *temp = '\0';

    if (*lineptr != '/')
      continue;

    lineptr ++;
    temp = type;

    while (*lineptr != ' ' && *lineptr != '\t' && *lineptr != '\n' &&
           *lineptr != '\0' && (temp - type + 1) < MIME_MAX_TYPE)
      *temp++ = (char)tolower(*lineptr++ & 255);

    *temp = '\0';

    if (*lineptr == '\0' || *lineptr == '\n')
      continue;

    if ((dsttype = mimeType(mime, super, type)) == NULL)
    {
      DEBUG_printf(("3mime_load_convs: Destination type %s/%s not found.",
                    super, type));
      continue;
    }

   /*
    * Then get the cost and filter program...
    */

    while (*lineptr == ' ' || *lineptr == '\t')
      lineptr ++;

    if (*lineptr < '0' || *lineptr > '9')
      continue;

    cost = atoi(lineptr);

    while (*lineptr != ' ' && *lineptr != '\t' && *lineptr != '\0')
      lineptr ++;
    while (*lineptr == ' ' || *lineptr == '\t')
      lineptr ++;

    if (*lineptr == '\0' || *lineptr == '\n')
      continue;

    filter = lineptr;

    if (strcmp(filter, "-"))
    {
     /*
      * Verify that the filter exists and is executable...
      */

      if (!mime_add_fcache(filtercache, filter, filterpath))
      {
        DEBUG_printf(("mime_load_convs: Filter %s not found in %s.", filter,
	              filterpath));
        _mimeError(mime, "Filter \"%s\" not found.", filter);
        continue;
      }
    }

   /*
    * Finally, get the source super-type and type names from the beginning of
    * the line.  We do it here so we can support wildcards...
    */

    lineptr = line;
    temp    = super;

    while (*lineptr != '/' && *lineptr != '\n' && *lineptr != '\0' &&
           (temp - super + 1) < MIME_MAX_SUPER)
      *temp++ = (char)tolower(*lineptr++ & 255);

    *temp = '\0';

    if (*lineptr != '/')
      continue;

    lineptr ++;
    temp = type;

    while (*lineptr != ' ' && *lineptr != '\t' && *lineptr != '\n' &&
           *lineptr != '\0' && (temp - type + 1) < MIME_MAX_TYPE)
      *temp++ = (char)tolower(*lineptr++ & 255);

    *temp = '\0';

    if (!strcmp(super, "*") && !strcmp(type, "*"))
    {
     /*
      * Force * / * to be "application/octet-stream"...
      */

      strlcpy(super, "application", sizeof(super));
      strlcpy(type, "octet-stream", sizeof(type));
    }

   /*
    * Add the filter to the MIME database, supporting wildcards as needed...
    */

    for (temptype = (mime_type_t *)cupsArrayFirst(mime->types);
         temptype;
	 temptype = (mime_type_t *)cupsArrayNext(mime->types))
      if ((super[0] == '*' || !strcmp(temptype->super, super)) &&
          (type[0] == '*' || !strcmp(temptype->type, type)))
	mimeAddFilter(mime, temptype, dsttype, cost, filter);
  }

  cupsFileClose(fp);
}
Beispiel #18
0
static cupsd_txt_t			/* O - TXT record */
dnssdBuildTxtRecord(
    cupsd_printer_t *p,			/* I - Printer information */
    int             for_lpd)		/* I - 1 = LPD, 0 = IPP */
{
  int		i,			/* Looping var */
		count;			/* Count of key/value pairs */
  char		admin_hostname[256],	/* Hostname for admin page */
		adminurl_str[256],	/* URL for the admin page */
		type_str[32],		/* Type to string buffer */
		state_str[32],		/* State to string buffer */
		rp_str[1024],		/* Queue name string buffer */
		air_str[1024],		/* auth-info-required string buffer */
		*keyvalue[32][2],	/* Table of key/value pairs */
                *ptr;                   /* Pointer in string */
  cupsd_txt_t	txt;			/* TXT record */
  cupsd_listener_t *lis;                /* Current listener */
  const char    *admin_scheme = "http"; /* Admin page URL scheme */


 /*
  * Load up the key value pairs...
  */

  count = 0;

  if (!for_lpd || (BrowseLocalProtocols & BROWSE_LPD))
  {
    keyvalue[count  ][0] = "txtvers";
    keyvalue[count++][1] = "1";

    keyvalue[count  ][0] = "qtotal";
    keyvalue[count++][1] = "1";

    keyvalue[count  ][0] = "rp";
    keyvalue[count++][1] = rp_str;
    if (for_lpd)
      strlcpy(rp_str, p->name, sizeof(rp_str));
    else
      snprintf(rp_str, sizeof(rp_str), "%s/%s",
	       (p->type & CUPS_PRINTER_CLASS) ? "classes" : "printers",
	       p->name);

    keyvalue[count  ][0] = "ty";
    keyvalue[count++][1] = p->make_model ? p->make_model : "Unknown";

   /*
    * Get the hostname for the admin page...
    */

    if (strchr(DNSSDHostName, '.'))
    {
     /*
      * Use the provided hostname, but make sure it ends with a period...
      */

      if ((ptr = DNSSDHostName + strlen(DNSSDHostName) - 1) >= DNSSDHostName && *ptr == '.')
        strlcpy(admin_hostname, DNSSDHostName, sizeof(admin_hostname));
      else
        snprintf(admin_hostname, sizeof(admin_hostname), "%s.", DNSSDHostName);
    }
    else
    {
     /*
      * Unqualified hostname gets ".local." added to it...
      */

      snprintf(admin_hostname, sizeof(admin_hostname), "%s.local.", DNSSDHostName);
    }

   /*
    * Get the URL scheme for the admin page...
    */

#  ifdef HAVE_SSL
    for (lis = (cupsd_listener_t *)cupsArrayFirst(Listeners); lis; lis = (cupsd_listener_t *)cupsArrayNext(Listeners))
    {
      if (lis->encryption != HTTP_ENCRYPTION_NEVER)
      {
        admin_scheme = "https";
        break;
      }
    }
#  endif /* HAVE_SSL */

    httpAssembleURIf(HTTP_URI_CODING_ALL, adminurl_str, sizeof(adminurl_str), admin_scheme,  NULL, admin_hostname, DNSSDPort, "/%s/%s", (p->type & CUPS_PRINTER_CLASS) ? "classes" : "printers", p->name);
    keyvalue[count  ][0] = "adminurl";
    keyvalue[count++][1] = adminurl_str;

    if (p->location)
    {
      keyvalue[count  ][0] = "note";
      keyvalue[count++][1] = p->location;
    }

    keyvalue[count  ][0] = "priority";
    keyvalue[count++][1] = for_lpd ? "100" : "0";

    keyvalue[count  ][0] = "product";
    keyvalue[count++][1] = p->pc && p->pc->product ? p->pc->product : "Unknown";

    keyvalue[count  ][0] = "pdl";
    keyvalue[count++][1] = p->pdl ? p->pdl : "application/postscript";

    if (get_auth_info_required(p, air_str, sizeof(air_str)))
    {
      keyvalue[count  ][0] = "air";
      keyvalue[count++][1] = air_str;
    }

    keyvalue[count  ][0] = "UUID";
    keyvalue[count++][1] = p->uuid + 9;

  #ifdef HAVE_SSL
    keyvalue[count  ][0] = "TLS";
    keyvalue[count++][1] = "1.2";
  #endif /* HAVE_SSL */

    if (p->type & CUPS_PRINTER_FAX)
    {
      keyvalue[count  ][0] = "Fax";
      keyvalue[count++][1] = "T";
      keyvalue[count  ][0] = "rfo";
      keyvalue[count++][1] = rp_str;
    }

    if (p->type & CUPS_PRINTER_COLOR)
    {
      keyvalue[count  ][0] = "Color";
      keyvalue[count++][1] = (p->type & CUPS_PRINTER_COLOR) ? "T" : "F";
    }

    if (p->type & CUPS_PRINTER_DUPLEX)
    {
      keyvalue[count  ][0] = "Duplex";
      keyvalue[count++][1] = (p->type & CUPS_PRINTER_DUPLEX) ? "T" : "F";
    }

    if (p->type & CUPS_PRINTER_STAPLE)
    {
      keyvalue[count  ][0] = "Staple";
      keyvalue[count++][1] = (p->type & CUPS_PRINTER_STAPLE) ? "T" : "F";
    }

    if (p->type & CUPS_PRINTER_COPIES)
    {
      keyvalue[count  ][0] = "Copies";
      keyvalue[count++][1] = (p->type & CUPS_PRINTER_COPIES) ? "T" : "F";
    }

    if (p->type & CUPS_PRINTER_COLLATE)
    {
      keyvalue[count  ][0] = "Collate";
      keyvalue[count++][1] = (p->type & CUPS_PRINTER_COLLATE) ? "T" : "F";
    }

    if (p->type & CUPS_PRINTER_PUNCH)
    {
      keyvalue[count  ][0] = "Punch";
      keyvalue[count++][1] = (p->type & CUPS_PRINTER_PUNCH) ? "T" : "F";
    }

    if (p->type & CUPS_PRINTER_BIND)
    {
      keyvalue[count  ][0] = "Bind";
      keyvalue[count++][1] = (p->type & CUPS_PRINTER_BIND) ? "T" : "F";
    }

    if (p->type & CUPS_PRINTER_SORT)
    {
      keyvalue[count  ][0] = "Sort";
      keyvalue[count++][1] = (p->type & CUPS_PRINTER_SORT) ? "T" : "F";
    }

    if (p->type & CUPS_PRINTER_MFP)
    {
      keyvalue[count  ][0] = "Scan";
      keyvalue[count++][1] = (p->type & CUPS_PRINTER_MFP) ? "T" : "F";
    }

    snprintf(type_str, sizeof(type_str), "0x%X", p->type | CUPS_PRINTER_REMOTE);
    snprintf(state_str, sizeof(state_str), "%d", p->state);

    keyvalue[count  ][0] = "printer-state";
    keyvalue[count++][1] = state_str;

    keyvalue[count  ][0] = "printer-type";
    keyvalue[count++][1] = type_str;
  }

 /*
  * Then pack them into a proper txt record...
  */

#  ifdef HAVE_DNSSD
  TXTRecordCreate(&txt, 0, NULL);

  for (i = 0; i < count; i ++)
  {
    size_t len = strlen(keyvalue[i][1]);

    if (len < 256)
      TXTRecordSetValue(&txt, keyvalue[i][0], (uint8_t)len, keyvalue[i][1]);
  }

#  else
  for (i = 0, txt = NULL; i < count; i ++)
    txt = avahi_string_list_add_printf(txt, "%s=%s", keyvalue[i][0],
                                       keyvalue[i][1]);
#  endif /* HAVE_DNSSD */

  return (txt);
}
Beispiel #19
0
void
cupsdSaveAllClasses(void)
{
  cups_file_t		*fp;		/* classes.conf file */
  char			temp[1024],	/* Temporary string */
			backup[1024],	/* printers.conf.O file */
			value[2048];	/* Value string */
  cupsd_printer_t	*pclass;	/* Current printer class */
  int			i;		/* Looping var */
  time_t		curtime;	/* Current time */
  struct tm		*curdate;	/* Current date */
  cups_option_t		*option;	/* Current option */


 /*
  * Create the classes.conf file...
  */

  snprintf(temp, sizeof(temp), "%s/classes.conf", ServerRoot);
  snprintf(backup, sizeof(backup), "%s/classes.conf.O", ServerRoot);

  if (rename(temp, backup))
  {
    if (errno != ENOENT)
      cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to backup classes.conf - %s",
                      strerror(errno));
  }

  if ((fp = cupsFileOpen(temp, "w")) == NULL)
  {
    cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to save classes.conf - %s",
                    strerror(errno));

    if (rename(backup, temp))
      cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to restore classes.conf - %s",
                      strerror(errno));
    return;
  }
  else
    cupsdLogMessage(CUPSD_LOG_INFO, "Saving classes.conf...");

 /*
  * Restrict access to the file...
  */

  fchown(cupsFileNumber(fp), RunUser, Group);
  fchmod(cupsFileNumber(fp), 0600);

 /*
  * Write a small header to the file...
  */

  curtime = time(NULL);
  curdate = localtime(&curtime);
  strftime(temp, sizeof(temp) - 1, "%Y-%m-%d %H:%M", curdate);

  cupsFilePuts(fp, "# Class configuration file for " CUPS_SVERSION "\n");
  cupsFilePrintf(fp, "# Written by cupsd on %s\n", temp);
  cupsFilePuts(fp, "# DO NOT EDIT THIS FILE WHEN CUPSD IS RUNNING\n");

 /*
  * Write each local class known to the system...
  */

  for (pclass = (cupsd_printer_t *)cupsArrayFirst(Printers);
       pclass;
       pclass = (cupsd_printer_t *)cupsArrayNext(Printers))
  {
   /*
    * Skip remote destinations and regular printers...
    */

    if ((pclass->type & CUPS_PRINTER_REMOTE) ||
        (pclass->type & CUPS_PRINTER_IMPLICIT) ||
        !(pclass->type & CUPS_PRINTER_CLASS))
      continue;

   /*
    * Write printers as needed...
    */

    if (pclass == DefaultPrinter)
      cupsFilePrintf(fp, "<DefaultClass %s>\n", pclass->name);
    else
      cupsFilePrintf(fp, "<Class %s>\n", pclass->name);

    if (pclass->num_auth_info_required > 0)
    {
      switch (pclass->num_auth_info_required)
      {
        case 1 :
            strlcpy(value, pclass->auth_info_required[0], sizeof(value));
	    break;

        case 2 :
            snprintf(value, sizeof(value), "%s,%s",
	             pclass->auth_info_required[0],
		     pclass->auth_info_required[1]);
	    break;

        case 3 :
	default :
            snprintf(value, sizeof(value), "%s,%s,%s",
	             pclass->auth_info_required[0],
		     pclass->auth_info_required[1],
		     pclass->auth_info_required[2]);
	    break;
      }

      cupsFilePutConf(fp, "AuthInfoRequired", value);
    }

    if (pclass->info)
      cupsFilePutConf(fp, "Info", pclass->info);

    if (pclass->location)
      cupsFilePutConf(fp, "Location", pclass->location);

    if (pclass->state == IPP_PRINTER_STOPPED)
      cupsFilePuts(fp, "State Stopped\n");
    else
      cupsFilePuts(fp, "State Idle\n");

    cupsFilePrintf(fp, "StateTime %d\n", (int)pclass->state_time);

    if (pclass->accepting)
      cupsFilePuts(fp, "Accepting Yes\n");
    else
      cupsFilePuts(fp, "Accepting No\n");

    if (pclass->shared)
      cupsFilePuts(fp, "Shared Yes\n");
    else
      cupsFilePuts(fp, "Shared No\n");

    snprintf(value, sizeof(value), "%s %s", pclass->job_sheets[0],
             pclass->job_sheets[1]);
    cupsFilePutConf(fp, "JobSheets", value);

    for (i = 0; i < pclass->num_printers; i ++)
      cupsFilePrintf(fp, "Printer %s\n", pclass->printers[i]->name);

    cupsFilePrintf(fp, "QuotaPeriod %d\n", pclass->quota_period);
    cupsFilePrintf(fp, "PageLimit %d\n", pclass->page_limit);
    cupsFilePrintf(fp, "KLimit %d\n", pclass->k_limit);

    for (i = 0; i < pclass->num_users; i ++)
      cupsFilePutConf(fp, pclass->deny_users ? "DenyUser" : "AllowUser",
                      pclass->users[i]);

     if (pclass->op_policy)
      cupsFilePutConf(fp, "OpPolicy", pclass->op_policy);
    if (pclass->error_policy)
      cupsFilePutConf(fp, "ErrorPolicy", pclass->error_policy);

    for (i = pclass->num_options, option = pclass->options;
         i > 0;
	 i --, option ++)
    {
      snprintf(value, sizeof(value), "%s %s", option->name, option->value);
      cupsFilePutConf(fp, "Option", value);
    }

    cupsFilePuts(fp, "</Class>\n");
  }

  cupsFileClose(fp);
}
Beispiel #20
0
static void
list_group(ppd_file_t  *ppd,		/* I - PPD file */
           ppd_group_t *group)		/* I - Group to show */
{
  int		i, j;			/* Looping vars */
  ppd_option_t	*option;		/* Current option */
  ppd_choice_t	*choice;		/* Current choice */
  ppd_group_t	*subgroup;		/* Current subgroup */
  char		buffer[10240],		/* Option string buffer */
		*ptr;			/* Pointer into option string */


  for (i = group->num_options, option = group->options; i > 0; i --, option ++)
  {
    if (!_cups_strcasecmp(option->keyword, "PageRegion"))
      continue;

    snprintf(buffer, sizeof(buffer), "%s/%s:", option->keyword, option->text);

    for (j = option->num_choices, choice = option->choices,
             ptr = buffer + strlen(buffer);
         j > 0 && ptr < (buffer + sizeof(buffer) - 1);
	 j --, choice ++)
    {
      if (!_cups_strcasecmp(choice->choice, "Custom"))
      {
        ppd_coption_t	*coption;	/* Custom option */
        ppd_cparam_t	*cparam;	/* Custom parameter */
	static const char * const types[] =
	{				/* Parameter types */
	  "CURVE",
	  "INTEGER",
	  "INVCURVE",
	  "PASSCODE",
	  "PASSWORD",
	  "POINTS",
	  "REAL",
	  "STRING"
	};


        if ((coption = ppdFindCustomOption(ppd, option->keyword)) == NULL ||
	    cupsArrayCount(coption->params) == 0)
	  snprintf(ptr, sizeof(buffer) - (size_t)(ptr - buffer), " %sCustom", choice->marked ? "*" : "");
        else if (!_cups_strcasecmp(option->keyword, "PageSize") ||
	         !_cups_strcasecmp(option->keyword, "PageRegion"))
	  snprintf(ptr, sizeof(buffer) - (size_t)(ptr - buffer), " %sCustom.WIDTHxHEIGHT", choice->marked ? "*" : "");
        else
	{
	  cparam = (ppd_cparam_t *)cupsArrayFirst(coption->params);

	  if (cupsArrayCount(coption->params) == 1)
	    snprintf(ptr, sizeof(buffer) - (size_t)(ptr - buffer), " %sCustom.%s", choice->marked ? "*" : "", types[cparam->type]);
	  else
	  {
	    const char	*prefix;	/* Prefix string */


            if (choice->marked)
	      prefix = " *{";
	    else
	      prefix = " {";

	    while (cparam)
	    {
	      snprintf(ptr, sizeof(buffer) - (size_t)(ptr - buffer), "%s%s=%s", prefix, cparam->name, types[cparam->type]);
	      cparam = (ppd_cparam_t *)cupsArrayNext(coption->params);
	      prefix = " ";
	      ptr += strlen(ptr);
	    }

            if (ptr < (buffer + sizeof(buffer) - 1))
	      strlcpy(ptr, "}", sizeof(buffer) - (size_t)(ptr - buffer));
	  }
	}
      }
      else if (choice->marked)
        snprintf(ptr, sizeof(buffer) - (size_t)(ptr - buffer), " *%s", choice->choice);
      else
        snprintf(ptr, sizeof(buffer) - (size_t)(ptr - buffer), " %s", choice->choice);

      ptr += strlen(ptr);
    }

    _cupsLangPuts(stdout, buffer);
  }

  for (i = group->num_subgroups, subgroup = group->subgroups; i > 0; i --, subgroup ++)
    list_group(ppd, subgroup);
}
Beispiel #21
0
static void
write_index(const char   *path,		/* I - File to write */
            help_index_t *hi)		/* I - Index of files */
{
  cups_file_t		*fp;		/* Output file */
  help_node_t		*node;		/* Current help node */
  _cups_section_t	*section,	/* Current section */
			key;		/* Section search key */
  _cups_html_t		*html;		/* Current HTML file */
  cups_array_t		*sections,	/* Sections in index */
			*sections_files,/* Sections sorted by size */
			*columns[3];	/* Columns in final HTML file */
  int			column,		/* Current column */
			lines[3],	/* Number of lines in each column */
			min_column,	/* Smallest column */
			min_lines;	/* Smallest number of lines */


 /*
  * Build an array of sections and their files.
  */

  sections = cupsArrayNew((cups_array_func_t)compare_sections, NULL);

  for (node = (help_node_t *)cupsArrayFirst(hi->nodes);
       node;
       node = (help_node_t *)cupsArrayNext(hi->nodes))
  {
    if (node->anchor)
      continue;

    key.name = node->section ? node->section : "Miscellaneous";
    if ((section = (_cups_section_t *)cupsArrayFind(sections, &key)) == NULL)
    {
      section        = (_cups_section_t *)calloc(1, sizeof(_cups_section_t));
      section->name  = key.name;
      section->files = cupsArrayNew((cups_array_func_t)compare_html, NULL);

      cupsArrayAdd(sections, section);
    }

    html = (_cups_html_t *)calloc(1, sizeof(_cups_html_t));
    html->path  = node->filename;
    html->title = node->text;

    cupsArrayAdd(section->files, html);
  }

 /*
  * Build a sorted list of sections based on the number of files in each section
  * and the section name...
  */

  sections_files = cupsArrayNew((cups_array_func_t)compare_sections_files,
                                NULL);
  for (section = (_cups_section_t *)cupsArrayFirst(sections);
       section;
       section = (_cups_section_t *)cupsArrayNext(sections))
    cupsArrayAdd(sections_files, section);

 /*
  * Then build three columns to hold everything, trying to balance the number of
  * lines in each column...
  */

  for (column = 0; column < 3; column ++)
  {
    columns[column] = cupsArrayNew((cups_array_func_t)compare_sections, NULL);
    lines[column]   = 0;
  }

  for (section = (_cups_section_t *)cupsArrayFirst(sections_files);
       section;
       section = (_cups_section_t *)cupsArrayNext(sections_files))
  {
    for (min_column = 0, min_lines = lines[0], column = 1;
         column < 3;
	 column ++)
    {
      if (lines[column] < min_lines)
      {
        min_column = column;
        min_lines  = lines[column];
      }
    }

    cupsArrayAdd(columns[min_column], section);
    lines[min_column] += cupsArrayCount(section->files) + 2;
  }

 /*
  * Write the HTML file...
  */

  if ((fp = cupsFileOpen(path, "w")) == NULL)
  {
    fprintf(stderr, "makedocset: Unable to create %s: %s\n", path,
            strerror(errno));
    exit(1);
  }

  cupsFilePuts(fp, "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 "
                   "Transitional//EN\" "
		   "\"http://www.w3.org/TR/html4/loose.dtd\">\n"
		   "<html>\n"
		   "<head>\n"
		   "<title>CUPS Documentation</title>\n"
		   "<link rel='stylesheet' type='text/css' "
		   "href='cups-printable.css'>\n"
		   "</head>\n"
		   "<body>\n"
		   "<h1 class='title'>CUPS Documentation</h1>\n"
		   "<table width='100%' summary=''>\n"
		   "<tr>\n");

  for (column = 0; column < 3; column ++)
  {
    if (column)
      cupsFilePuts(fp, "<td>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</td>\n");

    cupsFilePuts(fp, "<td valign='top' width='33%'>");
    for (section = (_cups_section_t *)cupsArrayFirst(columns[column]);
         section;
	 section = (_cups_section_t *)cupsArrayNext(columns[column]))
    {
      cupsFilePrintf(fp, "<h2 class='title'>%s</h2>\n", section->name);
      for (html = (_cups_html_t *)cupsArrayFirst(section->files);
           html;
	   html = (_cups_html_t *)cupsArrayNext(section->files))
	cupsFilePrintf(fp, "<p class='compact'><a href='%s'>%s</a></p>\n",
	               html->path, html->title);
    }
    cupsFilePuts(fp, "</td>\n");
  }
  cupsFilePuts(fp, "</tr>\n"
                   "</table>\n"
		   "</body>\n"
		   "</html>\n");
  cupsFileClose(fp);
}
Beispiel #22
0
int					/* O - Number of options marked */
ppdCollect2(ppd_file_t    *ppd,		/* I - PPD file data */
            ppd_section_t section,	/* I - Section to collect */
            float         min_order,	/* I - Minimum OrderDependency value */
            ppd_choice_t  ***choices)	/* O - Pointers to choices */
{
    ppd_choice_t	*c;			/* Current choice */
    ppd_section_t	csection;		/* Current section */
    float		corder;			/* Current OrderDependency value */
    int		count;			/* Number of choices collected */
    ppd_choice_t	**collect;		/* Collected choices */
    float		*orders;		/* Collected order values */


    DEBUG_printf(("ppdCollect2(ppd=%p, section=%d, min_order=%f, choices=%p)",
                  ppd, section, min_order, choices));

    if (!ppd || !choices)
    {
        if (choices)
            *choices = NULL;

        return (0);
    }

    /*
     * Allocate memory for up to N selected choices...
     */

    count = 0;
    if ((collect = calloc(sizeof(ppd_choice_t *),
                          cupsArrayCount(ppd->marked))) == NULL)
    {
        *choices = NULL;
        return (0);
    }

    if ((orders = calloc(sizeof(float), cupsArrayCount(ppd->marked))) == NULL)
    {
        *choices = NULL;
        free(collect);
        return (0);
    }

    /*
     * Loop through all options and add choices as needed...
     */

    for (c = (ppd_choice_t *)cupsArrayFirst(ppd->marked);
            c;
            c = (ppd_choice_t *)cupsArrayNext(ppd->marked))
    {
        csection = c->option->section;
        corder   = c->option->order;

        if (!strcmp(c->choice, "Custom"))
        {
            ppd_attr_t	*attr;		/* NonUIOrderDependency value */
            float		aorder;		/* Order value */
            char		asection[17],	/* Section name */
                        amain[PPD_MAX_NAME + 1],
                        aoption[PPD_MAX_NAME];
            /* *CustomFoo and True */


            for (attr = ppdFindAttr(ppd, "NonUIOrderDependency", NULL);
                    attr;
                    attr = ppdFindNextAttr(ppd, "NonUIOrderDependency", NULL))
                if (attr->value &&
                        sscanf(attr->value, "%f%16s%41s%40s", &aorder, asection, amain,
                               aoption) == 4 &&
                        !strncmp(amain, "*Custom", 7) &&
                        !strcmp(amain + 7, c->option->keyword) && !strcmp(aoption, "True"))
                {
                    /*
                     * Use this NonUIOrderDependency...
                     */

                    corder = aorder;

                    if (!strcmp(asection, "DocumentSetup"))
                        csection = PPD_ORDER_DOCUMENT;
                    else if (!strcmp(asection, "ExitServer"))
                        csection = PPD_ORDER_EXIT;
                    else if (!strcmp(asection, "JCLSetup"))
                        csection = PPD_ORDER_JCL;
                    else if (!strcmp(asection, "PageSetup"))
                        csection = PPD_ORDER_PAGE;
                    else if (!strcmp(asection, "Prolog"))
                        csection = PPD_ORDER_PROLOG;
                    else
                        csection = PPD_ORDER_ANY;

                    break;
                }
        }

        if (csection == section && corder >= min_order)
        {
            collect[count] = c;
            orders[count]  = corder;
            count ++;
        }
    }

    /*
     * If we have more than 1 marked choice, sort them...
     */

    if (count > 1)
    {
        int i, j;				/* Looping vars */

        for (i = 0; i < (count - 1); i ++)
            for (j = i + 1; j < count; j ++)
                if (orders[i] > orders[j])
                {
                    c          = collect[i];
                    corder     = orders[i];
                    collect[i] = collect[j];
                    orders[i]  = orders[j];
                    collect[j] = c;
                    orders[j]  = corder;
                }
    }

    free(orders);

    DEBUG_printf(("2ppdCollect2: %d marked choices...", count));

    /*
     * Return the array and number of choices; if 0, free the array since
     * it isn't needed.
     */

    if (count > 0)
    {
        *choices = collect;
        return (count);
    }
    else
    {
        *choices = NULL;
        free(collect);
        return (0);
    }
}
Beispiel #23
0
int					/* O - Exit code */
main(int  argc,				/* I - Number of command-line args */
     char *argv[])			/* I - Command-line arguments */
{
  const char	*server_bin;		/* CUPS_SERVERBIN environment variable */
  char		backends[1024];		/* Location of backends */
  int		request_id;		/* Request ID */
  int		count;			/* Number of devices from backend */
  int		compat;			/* Compatibility device? */
  char		*backend_argv[2];	/* Arguments for backend */
  cups_file_t	*fp;			/* Pipe to device backend */
  int		pid;			/* Process ID of backend */
  cups_dir_t	*dir;			/* Directory pointer */
  cups_dentry_t *dent;			/* Directory entry */
  char		filename[1024],		/* Name of backend */
		line[2048],		/* Line from backend */
		dclass[64],		/* Device class */
		uri[1024],		/* Device URI */
		info[128],		/* Device info */
		make_model[256],	/* Make and model */
		device_id[1024];	/* 1284 device ID */
  int		num_options;		/* Number of options */
  cups_option_t	*options;		/* Options */
  const char	*requested;		/* requested-attributes option */
  int		send_class,		/* Send device-class attribute? */
		send_info,		/* Send device-info attribute? */
		send_make_and_model,	/* Send device-make-and-model attribute? */
		send_uri,		/* Send device-uri attribute? */
		send_id;		/* Send device-id attribute? */
  dev_info_t	*dev;			/* Current device */
#if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
  struct sigaction action;		/* Actions for POSIX signals */
#endif /* HAVE_SIGACTION && !HAVE_SIGSET */


  setbuf(stderr, NULL);

 /*
  * Check the command-line...
  */

  if (argc > 1)
    request_id = atoi(argv[1]);
  else
    request_id = 1;

  if (argc != 5)
  {
    fputs("Usage: cups-deviced request-id limit user-id options\n", stderr);

    return (1);
  }

  if (request_id < 1)
  {
    fprintf(stderr, "cups-deviced: Bad request ID %d!\n", request_id);

    return (1);
  }

  normal_user = atoi(argv[3]);
  if (normal_user <= 0)
  {
    fprintf(stderr, "cups-deviced: Bad user %d!\n", normal_user);

    return (1);
  }

  num_options = cupsParseOptions(argv[4], 0, &options);
  requested   = cupsGetOption("requested-attributes", num_options, options);

  if (!requested || strstr(requested, "all"))
  {
    send_class          = 1;
    send_info           = 1;
    send_make_and_model = 1;
    send_uri            = 1;
    send_id             = 1;
  }
  else
  {
    send_class          = strstr(requested, "device-class") != NULL;
    send_info           = strstr(requested, "device-info") != NULL;
    send_make_and_model = strstr(requested, "device-make-and-model") != NULL;
    send_uri            = strstr(requested, "device-uri") != NULL;
    send_id             = strstr(requested, "device-id") != NULL;
  }

 /*
  * Try opening the backend directory...
  */

  if ((server_bin = getenv("CUPS_SERVERBIN")) == NULL)
    server_bin = CUPS_SERVERBIN;

  snprintf(backends, sizeof(backends), "%s/backend", server_bin);

  if ((dir = cupsDirOpen(backends)) == NULL)
  {
    fprintf(stderr, "ERROR: [cups-deviced] Unable to open backend directory "
                    "\"%s\": %s", backends, strerror(errno));

    return (1);
  }

 /*
  * Setup the devices array...
  */

  devs = cupsArrayNew((cups_array_func_t)compare_devs, NULL);

 /*
  * Loop through all of the device backends...
  */

  while ((dent = cupsDirRead(dir)) != NULL)
  {
   /*
    * Skip entries that are not executable files...
    */

    if (!S_ISREG(dent->fileinfo.st_mode) ||
        (dent->fileinfo.st_mode & (S_IRUSR | S_IXUSR)) != (S_IRUSR | S_IXUSR))
      continue;

   /*
    * Change effective users depending on the backend permissions...
    */

    snprintf(filename, sizeof(filename), "%s/%s", backends, dent->filename);

   /*
    * Backends without permissions for normal users run as root,
    * all others run as the unprivileged user...
    */

    backend_argv[0] = dent->filename;
    backend_argv[1] = NULL;

    fp = cupsdPipeCommand(&pid, filename, backend_argv,
                          (dent->fileinfo.st_mode & (S_IRWXG | S_IRWXO))
		              ? normal_user : 0);

   /*
    * Collect the output from the backend...
    */

    if (fp)
    {
     /*
      * Set an alarm for the first read from the backend; this avoids
      * problems when a backend is hung getting device information.
      */

#ifdef HAVE_SIGSET /* Use System V signals over POSIX to avoid bugs */
      sigset(SIGALRM, sigalrm_handler);
#elif defined(HAVE_SIGACTION)
      memset(&action, 0, sizeof(action));

      sigemptyset(&action.sa_mask);
      sigaddset(&action.sa_mask, SIGALRM);
      action.sa_handler = sigalrm_handler;
      sigaction(SIGALRM, &action, NULL);
#else
      signal(SIGALRM, sigalrm_handler);
#endif /* HAVE_SIGSET */

      alarm_tripped = 0;
      count         = 0;
      compat        = !strcmp(dent->filename, "smb");

      alarm(30);

      while (cupsFileGets(fp, line, sizeof(line)))
      {
       /*
        * Reset the alarm clock...
	*/

        alarm(30);

       /*
        * Each line is of the form:
	*
	*   class URI "make model" "name" ["1284 device ID"]
	*/

        device_id[0] = '\0';

        if (!strncasecmp(line, "Usage", 5))
	  compat = 1;
        else if (sscanf(line,
	                "%63s%1023s%*[ \t]\"%255[^\"]\"%*[ \t]\"%127[^\"]\""
			"%*[ \t]\"%1023[^\"]",
	                dclass, uri, make_model, info, device_id) < 4)
        {
	 /*
	  * Bad format; strip trailing newline and write an error message.
	  */

          if (line[strlen(line) - 1] == '\n')
	    line[strlen(line) - 1] = '\0';

	  fprintf(stderr, "ERROR: [cups-deviced] Bad line from \"%s\": %s\n",
	          dent->filename, line);
          compat = 1;
	  break;
        }
	else
	{
	 /*
	  * Add the device to the array of available devices...
	  */

          dev = add_dev(dclass, make_model, info, uri, device_id);
	  if (!dev)
	  {
            cupsDirClose(dir);
	    cupsFileClose(fp);
            kill(pid, SIGTERM);
	    return (1);
	  }

          fprintf(stderr, "DEBUG: [cups-deviced] Added device \"%s\"...\n",
	          uri);
	  count ++;
	}
      }

     /*
      * Turn the alarm clock off and close the pipe to the command...
      */

      alarm(0);

      if (alarm_tripped)
        fprintf(stderr, "WARNING: [cups-deviced] Backend \"%s\" did not "
	                "respond within 30 seconds!\n", dent->filename);

      cupsFileClose(fp);
      kill(pid, SIGTERM);

     /*
      * Hack for backends that don't support the CUPS 1.1 calling convention:
      * add a network device with the method == backend name.
      */

      if (count == 0 && compat)
      {
	snprintf(line, sizeof(line), "Unknown Network Device (%s)",
	         dent->filename);

        dev = add_dev("network", line, "Unknown", dent->filename, "");
	if (!dev)
	{
          cupsDirClose(dir);
	  return (1);
	}

        fprintf(stderr, "DEBUG: [cups-deviced] Compatibility device "
	                "\"%s\"...\n", dent->filename);
      }
    }
    else
      fprintf(stderr, "WARNING: [cups-deviced] Unable to execute \"%s\" "
                      "backend: %s\n", dent->filename, strerror(errno));
  }

  cupsDirClose(dir);

 /*
  * Output the list of devices...
  */

  puts("Content-Type: application/ipp\n");

  cupsdSendIPPHeader(IPP_OK, request_id);
  cupsdSendIPPGroup(IPP_TAG_OPERATION);
  cupsdSendIPPString(IPP_TAG_CHARSET, "attributes-charset", "utf-8");
  cupsdSendIPPString(IPP_TAG_LANGUAGE, "attributes-natural-language", "en-US");

  if ((count = atoi(argv[2])) <= 0)
    count = cupsArrayCount(devs);

  if (count > cupsArrayCount(devs))
    count = cupsArrayCount(devs);

  for (dev = (dev_info_t *)cupsArrayFirst(devs);
       count > 0;
       count --, dev = (dev_info_t *)cupsArrayNext(devs))
  {
   /*
    * Add strings to attributes...
    */

    cupsdSendIPPGroup(IPP_TAG_PRINTER);
    if (send_class)
      cupsdSendIPPString(IPP_TAG_KEYWORD, "device-class", dev->device_class);
    if (send_info)
      cupsdSendIPPString(IPP_TAG_TEXT, "device-info", dev->device_info);
    if (send_make_and_model)
      cupsdSendIPPString(IPP_TAG_TEXT, "device-make-and-model",
                	 dev->device_make_and_model);
    if (send_uri)
      cupsdSendIPPString(IPP_TAG_URI, "device-uri", dev->device_uri);
    if (send_id)
      cupsdSendIPPString(IPP_TAG_TEXT, "device-id", dev->device_id);
  }

  cupsdSendIPPTrailer();

 /*
  * Free the devices array and return...
  */

  for (dev = (dev_info_t *)cupsArrayFirst(devs);
       dev;
       dev = (dev_info_t *)cupsArrayNext(devs))
    free(dev);

  cupsArrayDelete(devs);

  return (0);
}