Exemple #1
0
void
ppdMarkDefaults(ppd_file_t *ppd)	/* I - PPD file record */
{
  int		i;			/* Looping variables */
  ppd_group_t	*g;			/* Current group */
  ppd_choice_t	*c;			/* Current choice */


  if (!ppd)
    return;

 /*
  * Clean out the marked array...
  */

  for (c = (ppd_choice_t *)cupsArrayFirst(ppd->marked);
       c;
       c = (ppd_choice_t *)cupsArrayNext(ppd->marked))
  {
    cupsArrayRemove(ppd->marked, c);
    c->marked = 0;
  }

 /*
  * Then repopulate it with the defaults...
  */

  for (i = ppd->num_groups, g = ppd->groups; i > 0; i --, g ++)
    ppd_defaults(ppd, g);
}
Exemple #2
0
void
serverCleanJobs(server_printer_t *printer)	/* I - Printer */
{
  server_job_t	*job;			/* Current job */
  time_t	cleantime;		/* Clean time */


  if (cupsArrayCount(printer->jobs) == 0)
    return;

  cleantime = time(NULL) - 60;

  _cupsRWLockWrite(&(printer->rwlock));
  for (job = (server_job_t *)cupsArrayFirst(printer->jobs);
       job;
       job = (server_job_t *)cupsArrayNext(printer->jobs))
    if (job->completed && job->completed < cleantime)
    {
      cupsArrayRemove(printer->jobs, job);
      serverDeleteJob(job);
    }
    else
      break;
  _cupsRWUnlock(&(printer->rwlock));
}
Exemple #3
0
const char *				/* O - Process name */
cupsdFinishProcess(int    pid,		/* I - Process ID */
                   char   *name,	/* I - Name buffer */
		   size_t namelen,	/* I - Size of name buffer */
		   int    *job_id)	/* O - Job ID pointer or NULL */
{
  cupsd_proc_t	key,			/* Search key */
		*proc;			/* Matching process */


  key.pid = pid;

  if ((proc = (cupsd_proc_t *)cupsArrayFind(process_array, &key)) != NULL)
  {
    if (job_id)
      *job_id = proc->job_id;

    strlcpy(name, proc->name, namelen);
    cupsArrayRemove(process_array, proc);
    free(proc);
  }
  else
  {
    if (job_id)
      *job_id = 0;

    strlcpy(name, "unknown", namelen);
  }

  cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdFinishProcess(pid=%d, name=%p, namelen=" CUPS_LLFMT ", job_id=%p(%d)) = \"%s\"", pid, name, CUPS_LLCAST namelen, job_id, job_id ? *job_id : 0, name);

  return (name);
}
Exemple #4
0
void
mimeDeleteType(mime_t      *mime,	/* I - MIME database */
	       mime_type_t *mt)		/* I - Type */
{
  if (!mime || !mt)
    return;

  cupsArrayRemove(mime->types, mt);

  delete_rules(mt->rules);
  free(mt);
}
Exemple #5
0
static void
cupsdNetIFFree(void)
{
  cupsd_netif_t	*current;		/* Current interface in array */


 /*
  * Loop through the interface list and free all the records...
  */

  for (current = (cupsd_netif_t *)cupsArrayFirst(NetIFList);
       current;
       current = (cupsd_netif_t *)cupsArrayNext(NetIFList))
  {
    cupsArrayRemove(NetIFList, current);
    free(current);
  }
}
void
mimeDeleteType(mime_t      *mime,	/* I - MIME database */
	       mime_type_t *mt)		/* I - Type */
{
  DEBUG_printf(("mimeDeleteType(mime=%p, mt=%p(%s/%s))", mime, mt,
                mt ? mt->super : "???", mt ? mt->type : "???"));

  if (!mime || !mt)
    return;

#ifdef DEBUG
  if (!cupsArrayFind(mime->types, mt))
    DEBUG_puts("1mimeDeleteFilter: Type not in MIME database.");
#endif /* DEBUG */

  cupsArrayRemove(mime->types, mt);

  mime_delete_rules(mt->rules);
  free(mt);
}
Exemple #7
0
void
mimeDeleteFilter(mime_t        *mime,	/* I - MIME database */
		 mime_filter_t *filter)	/* I - Filter */
{
  if (!mime || !filter)
    return;

  cupsArrayRemove(mime->filters, filter);
  free(filter);

 /*
  * Deleting a filter invalidates the source lookup cache used by
  * mimeFilter()...
  */

  if (mime->srcs)
  {
    cupsArrayDelete(mime->srcs);
    mime->srcs = NULL;
  }
}
Exemple #8
0
static void
dnssdRegisterCallback(
    DNSServiceRef	sdRef,		/* I - DNS Service reference */
    DNSServiceFlags	flags,		/* I - Reserved for future use */
    DNSServiceErrorType	errorCode,	/* I - Error code */
    const char		*name,     	/* I - Service name */
    const char		*regtype,  	/* I - Service type */
    const char		*domain,   	/* I - Domain. ".local" for now */
    void		*context)	/* I - Printer */
{
  cupsd_printer_t *p = (cupsd_printer_t *)context;
					/* Current printer */


  (void)sdRef;
  (void)flags;
  (void)domain;

  cupsdLogMessage(CUPSD_LOG_DEBUG2, "dnssdRegisterCallback(%s, %s) for %s (%s)",
                  name, regtype, p ? p->name : "Web Interface",
		  p ? (p->reg_name ? p->reg_name : "(null)") : "NA");

  if (errorCode)
  {
    cupsdLogMessage(CUPSD_LOG_ERROR,
		    "DNSServiceRegister failed with error %d", (int)errorCode);
    return;
  }
  else if (p && (!p->reg_name || _cups_strcasecmp(name, p->reg_name)))
  {
    cupsdLogMessage(CUPSD_LOG_INFO, "Using service name \"%s\" for \"%s\"",
                    name, p->name);

    cupsArrayRemove(DNSSDPrinters, p);
    cupsdSetString(&p->reg_name, name);
    cupsArrayAdd(DNSSDPrinters, p);

    LastEvent |= CUPSD_EVENT_PRINTER_MODIFIED;
  }
}
Exemple #9
0
void
cupsdDeleteAllListeners(void)
{
  cupsd_listener_t	*lis;		/* Current listening socket */


  for (lis = (cupsd_listener_t *)cupsArrayFirst(Listeners);
       lis;
       lis = (cupsd_listener_t *)cupsArrayNext(Listeners))
#if defined(HAVE_LAUNCHD) || defined(HAVE_SYSTEMD)
    if (!lis->on_demand)
#endif /* HAVE_LAUNCHD || HAVE_SYSTEMD */
    {
      cupsArrayRemove(Listeners, lis);
      free(lis);
    }

  if (cupsArrayCount(Listeners) == 0)
  {
    cupsArrayDelete(Listeners);
    Listeners = NULL;
  }
}
Exemple #10
0
static void
dnssdDeregisterPrinter(
    cupsd_printer_t *p,			/* I - Printer */
    int             clear_name,		/* I - Clear the name? */
    int             from_callback)	/* I - Called from callback? */

{
  cupsdLogMessage(CUPSD_LOG_DEBUG2,
                  "dnssdDeregisterPrinter(p=%p(%s), clear_name=%d)", p, p->name,
                  clear_name);

  if (p->ipp_srv)
  {
    dnssdDeregisterInstance(&p->ipp_srv, from_callback);

#  ifdef HAVE_DNSSD
#    ifdef HAVE_SSL
    dnssdDeregisterInstance(&p->ipps_srv, from_callback);
#    endif /* HAVE_SSL */
    dnssdDeregisterInstance(&p->printer_srv, from_callback);
#  endif /* HAVE_DNSSD */
  }

 /*
  * Remove the printer from the array of DNS-SD printers but keep the
  * registered name...
  */

  cupsArrayRemove(DNSSDPrinters, p);

 /*
  * Optionally clear the service name...
  */

  if (clear_name)
    cupsdClearString(&p->reg_name);
}
Exemple #11
0
void
cupsdDeleteSubscription(
    cupsd_subscription_t *sub,		/* I - Subscription object */
    int                  update)	/* I - 1 = update subscriptions.conf */
{
 /*
  * Close the pipe to the notifier as needed...
  */

  if (sub->pipe >= 0)
    close(sub->pipe);

 /*
  * Remove subscription from array...
  */

  cupsArrayRemove(Subscriptions, sub);

 /*
  * Free memory...
  */

  cupsdClearString(&(sub->owner));
  cupsdClearString(&(sub->recipient));

  cupsArrayDelete(sub->events);

  free(sub);

 /*
  * Update the subscriptions as needed...
  */

  if (update)
    cupsdMarkDirty(CUPSD_DIRTY_SUBSCRIPTIONS);
}
void
mimeDeleteFilter(mime_t        *mime,	/* I - MIME database */
		 mime_filter_t *filter)	/* I - Filter */
{
  DEBUG_printf(("mimeDeleteFilter(mime=%p, filter=%p(%s/%s->%s/%s, cost=%d, "
                "maxsize=" CUPS_LLFMT "))", mime, filter,
		filter ? filter->src->super : "???",
		filter ? filter->src->type : "???",
		filter ? filter->dst->super : "???",
		filter ? filter->dst->super : "???",
		filter ? filter->cost : -1,
		filter ? CUPS_LLCAST filter->maxsize : CUPS_LLCAST -1));

  if (!mime || !filter)
    return;

#ifdef DEBUG
  if (!cupsArrayFind(mime->filters, filter))
    DEBUG_puts("1mimeDeleteFilter: Filter not in MIME database.");
#endif /* DEBUG */

  cupsArrayRemove(mime->filters, filter);
  free(filter);

 /*
  * Deleting a filter invalidates the source lookup cache used by
  * mimeFilter()...
  */

  if (mime->srcs)
  {
    DEBUG_puts("1mimeDeleteFilter: Deleting source lookup cache.");
    cupsArrayDelete(mime->srcs);
    mime->srcs = NULL;
  }
}
Exemple #13
0
int					/* O - Exit status */
main(int  argc,				/* I - Number of command-line arguments */
     char *argv[])			/* I - Command-line arguments */
{
  int		i;			/* Looping var */
  cups_array_t	*array,			/* Test array */
		*dup_array;		/* Duplicate array */
  int		status;			/* Exit status */
  char		*text;			/* Text from array */
  char		word[256];		/* Word from file */
  double	start,			/* Start time */
		end;			/* End time */
  cups_dir_t	*dir;			/* Current directory */
  cups_dentry_t	*dent;			/* Directory entry */
  char		*saved[32];		/* Saved entries */
  void		*data;			/* User data for arrays */


 /*
  * No errors so far...
  */

  status = 0;

 /*
  * cupsArrayNew()
  */

  fputs("cupsArrayNew: ", stdout);

  data  = (void *)"testarray";
  array = cupsArrayNew((cups_array_func_t)strcmp, data);

  if (array)
    puts("PASS");
  else
  {
    puts("FAIL (returned NULL, expected pointer)");
    status ++;
  }

 /*
  * cupsArrayUserData()
  */

  fputs("cupsArrayUserData: ", stdout);
  if (cupsArrayUserData(array) == data)
    puts("PASS");
  else
  {
    printf("FAIL (returned %p instead of %p!)\n", cupsArrayUserData(array),
           data);
    status ++;
  }

 /*
  * cupsArrayAdd()
  */

  fputs("cupsArrayAdd: ", stdout);

  if (!cupsArrayAdd(array, strdup("One Fish")))
  {
    puts("FAIL (\"One Fish\")");
    status ++;
  }
  else
  {
    if (!cupsArrayAdd(array, strdup("Two Fish")))
    {
      puts("FAIL (\"Two Fish\")");
      status ++;
    }
    else
    {
      if (!cupsArrayAdd(array, strdup("Red Fish")))
      {
	puts("FAIL (\"Red Fish\")");
	status ++;
      }
      else
      {
        if (!cupsArrayAdd(array, strdup("Blue Fish")))
	{
	  puts("FAIL (\"Blue Fish\")");
	  status ++;
	}
	else
	  puts("PASS");
      }
    }
  }

 /*
  * cupsArrayCount()
  */

  fputs("cupsArrayCount: ", stdout);
  if (cupsArrayCount(array) == 4)
    puts("PASS");
  else
  {
    printf("FAIL (returned %d, expected 4)\n", cupsArrayCount(array));
    status ++;
  }

 /*
  * cupsArrayFirst()
  */

  fputs("cupsArrayFirst: ", stdout);
  if ((text = (char *)cupsArrayFirst(array)) != NULL &&
      !strcmp(text, "Blue Fish"))
    puts("PASS");
  else
  {
    printf("FAIL (returned \"%s\", expected \"Blue Fish\")\n", text);
    status ++;
  }

 /*
  * cupsArrayNext()
  */

  fputs("cupsArrayNext: ", stdout);
  if ((text = (char *)cupsArrayNext(array)) != NULL &&
      !strcmp(text, "One Fish"))
    puts("PASS");
  else
  {
    printf("FAIL (returned \"%s\", expected \"One Fish\")\n", text);
    status ++;
  }

 /*
  * cupsArrayLast()
  */

  fputs("cupsArrayLast: ", stdout);
  if ((text = (char *)cupsArrayLast(array)) != NULL &&
      !strcmp(text, "Two Fish"))
    puts("PASS");
  else
  {
    printf("FAIL (returned \"%s\", expected \"Two Fish\")\n", text);
    status ++;
  }

 /*
  * cupsArrayPrev()
  */

  fputs("cupsArrayPrev: ", stdout);
  if ((text = (char *)cupsArrayPrev(array)) != NULL &&
      !strcmp(text, "Red Fish"))
    puts("PASS");
  else
  {
    printf("FAIL (returned \"%s\", expected \"Red Fish\")\n", text);
    status ++;
  }

 /*
  * cupsArrayFind()
  */

  fputs("cupsArrayFind: ", stdout);
  if ((text = (char *)cupsArrayFind(array, (void *)"One Fish")) != NULL &&
      !strcmp(text, "One Fish"))
    puts("PASS");
  else
  {
    printf("FAIL (returned \"%s\", expected \"One Fish\")\n", text);
    status ++;
  }

 /*
  * cupsArrayCurrent()
  */

  fputs("cupsArrayCurrent: ", stdout);
  if ((text = (char *)cupsArrayCurrent(array)) != NULL &&
      !strcmp(text, "One Fish"))
    puts("PASS");
  else
  {
    printf("FAIL (returned \"%s\", expected \"One Fish\")\n", text);
    status ++;
  }

 /*
  * cupsArrayDup()
  */

  fputs("cupsArrayDup: ", stdout);
  if ((dup_array = cupsArrayDup(array)) != NULL &&
      cupsArrayCount(dup_array) == 4)
    puts("PASS");
  else
  {
    printf("FAIL (returned %p with %d elements, expected pointer with 4 elements)\n",
           dup_array, cupsArrayCount(dup_array));
    status ++;
  }

 /*
  * cupsArrayRemove()
  */

  fputs("cupsArrayRemove: ", stdout);
  if (cupsArrayRemove(array, (void *)"One Fish") &&
      cupsArrayCount(array) == 3)
    puts("PASS");
  else
  {
    printf("FAIL (returned 0 with %d elements, expected 1 with 4 elements)\n",
           cupsArrayCount(array));
    status ++;
  }

 /*
  * cupsArrayClear()
  */

  fputs("cupsArrayClear: ", stdout);
  cupsArrayClear(array);
  if (cupsArrayCount(array) == 0)
    puts("PASS");
  else
  {
    printf("FAIL (%d elements, expected 0 elements)\n",
           cupsArrayCount(array));
    status ++;
  }

 /*
  * Now load this source file and grab all of the unique words...
  */

  fputs("Load unique words: ", stdout);
  fflush(stdout);

  start = get_seconds();

  if ((dir = cupsDirOpen(".")) == NULL)
  {
    puts("FAIL (cupsDirOpen failed)");
    status ++;
  }
  else
  {
    while ((dent = cupsDirRead(dir)) != NULL)
    {
      i = strlen(dent->filename) - 2;

      if (i > 0 && dent->filename[i] == '.' &&
          (dent->filename[i + 1] == 'c' ||
	   dent->filename[i + 1] == 'h'))
	load_words(dent->filename, array);
    }

    cupsDirClose(dir);

    end = get_seconds();

    printf("%d words in %.3f seconds (%.0f words/sec), ", cupsArrayCount(array),
           end - start, cupsArrayCount(array) / (end - start));
    fflush(stdout);

    for (text = (char *)cupsArrayFirst(array); text;)
    {
     /*
      * Copy this word to the word buffer (safe because we strdup'd from
      * the same buffer in the first place... :)
      */

      strlcpy(word, text, sizeof(word));

     /*
      * Grab the next word and compare...
      */

      if ((text = (char *)cupsArrayNext(array)) == NULL)
	break;

      if (strcmp(word, text) >= 0)
	break;
    }

    if (text)
    {
      printf("FAIL (\"%s\" >= \"%s\"!)\n", word, text);
      status ++;
    }
    else
      puts("PASS");
  }

 /*
  * Test deleting with iteration...
  */

  fputs("Delete While Iterating: ", stdout);

  text = (char *)cupsArrayFirst(array);
  cupsArrayRemove(array, text);
  free(text);

  text = (char *)cupsArrayNext(array);
  if (!text)
  {
    puts("FAIL (cupsArrayNext returned NULL!)");
    status ++;
  }
  else
    puts("PASS");

 /*
  * Test save/restore...
  */

  fputs("cupsArraySave: ", stdout);

  for (i = 0, text = (char *)cupsArrayFirst(array);
       i < 32;
       i ++, text = (char *)cupsArrayNext(array))
  {
    saved[i] = text;

    if (!cupsArraySave(array))
      break;
  }

  if (i < 32)
    printf("FAIL (depth = %d)\n", i);
  else
    puts("PASS");

  fputs("cupsArrayRestore: ", stdout);

  while (i > 0)
  {
    i --;

    text = cupsArrayRestore(array);
    if (text != saved[i])
      break;
  }

  if (i)
    printf("FAIL (depth = %d)\n", i);
  else
    puts("PASS");

 /*
  * Delete the arrays...
  */

  cupsArrayDelete(array);
  cupsArrayDelete(dup_array);

 /*
  * Test the array with string functions...
  */

  fputs("_cupsArrayNewStrings(\" \\t\\nfoo bar\\tboo\\nfar\", ' '): ", stdout);
  array = _cupsArrayNewStrings(" \t\nfoo bar\tboo\nfar", ' ');
  if (!array)
  {
    status = 1;
    puts("FAIL (unable to create array)");
  }
  else if (cupsArrayCount(array) != 4)
  {
    status = 1;
    printf("FAIL (got %d elements, expected 4)\n", cupsArrayCount(array));
  }
  else if (strcmp(text = (char *)cupsArrayFirst(array), "bar"))
  {
    status = 1;
    printf("FAIL (first element \"%s\", expected \"bar\")\n", text);
  }
  else if (strcmp(text = (char *)cupsArrayNext(array), "boo"))
  {
    status = 1;
    printf("FAIL (first element \"%s\", expected \"boo\")\n", text);
  }
  else if (strcmp(text = (char *)cupsArrayNext(array), "far"))
  {
    status = 1;
    printf("FAIL (first element \"%s\", expected \"far\")\n", text);
  }
  else if (strcmp(text = (char *)cupsArrayNext(array), "foo"))
  {
    status = 1;
    printf("FAIL (first element \"%s\", expected \"foo\")\n", text);
  }
  else
    puts("PASS");

  fputs("_cupsArrayAddStrings(array, \"foo2,bar2\", ','): ", stdout);
  _cupsArrayAddStrings(array, "foo2,bar2", ',');

  if (cupsArrayCount(array) != 6)
  {
    status = 1;
    printf("FAIL (got %d elements, expected 6)\n", cupsArrayCount(array));
  }
  else if (strcmp(text = (char *)cupsArrayFirst(array), "bar"))
  {
    status = 1;
    printf("FAIL (first element \"%s\", expected \"bar\")\n", text);
  }
  else if (strcmp(text = (char *)cupsArrayNext(array), "bar2"))
  {
    status = 1;
    printf("FAIL (first element \"%s\", expected \"bar2\")\n", text);
  }
  else if (strcmp(text = (char *)cupsArrayNext(array), "boo"))
  {
    status = 1;
    printf("FAIL (first element \"%s\", expected \"boo\")\n", text);
  }
  else if (strcmp(text = (char *)cupsArrayNext(array), "far"))
  {
    status = 1;
    printf("FAIL (first element \"%s\", expected \"far\")\n", text);
  }
  else if (strcmp(text = (char *)cupsArrayNext(array), "foo"))
  {
    status = 1;
    printf("FAIL (first element \"%s\", expected \"foo\")\n", text);
  }
  else if (strcmp(text = (char *)cupsArrayNext(array), "foo2"))
  {
    status = 1;
    printf("FAIL (first element \"%s\", expected \"foo2\")\n", text);
  }
  else
    puts("PASS");

  cupsArrayDelete(array);

 /*
  * Summarize the results and return...
  */

  if (!status)
    puts("\nALL TESTS PASSED!");
  else
    printf("\n%d TEST(S) FAILED!\n", status);

  return (status);
}
Exemple #14
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);
}
Exemple #15
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[17],		/* 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 */
		final_content_type[1024] = "",
					/* FINAL_CONTENT_TYPE */
		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 */


 /*
  * Figure out the final content type...
  */

  for (filter = (mime_filter_t *)cupsArrayLast(filters);
       filter && filter->dst;
       filter = (mime_filter_t *)cupsArrayPrev(filters))
    if (strcmp(filter->dst->super, "printer"))
      break;

  if (filter && filter->dst)
  {
    const char *ptr;			/* Pointer in type name */

    if ((ptr = strchr(filter->dst->type, '/')) != NULL)
      snprintf(final_content_type, sizeof(final_content_type),
	       "FINAL_CONTENT_TYPE=%s", ptr + 1);
    else
      snprintf(final_content_type, sizeof(final_content_type),
	       "FINAL_CONTENT_TYPE=%s/%s", filter->dst->super,
	       filter->dst->type);
  }

 /*
  * Remove NULL ("-") filters...
  */

  for (filter = (mime_filter_t *)cupsArrayFirst(filters);
       filter;
       filter = (mime_filter_t *)cupsArrayNext(filters))
    if (!strcmp(filter->filter, "-"))
      cupsArrayRemove(filters, filter);

 /*
  * 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] = "CHARSET=utf-8";
  if (final_content_type[0])
  {
    envp[15] = final_content_type;
    envp[16] = NULL;
  }
  else
    envp[15] = 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);
}
Exemple #16
0
static void
process_children(void)
{
  int		status;			/* Exit status of child */
  int		pid,			/* Process ID of child */
		job_id;			/* Job ID of child */
  cupsd_job_t	*job;			/* Current job */
  int		i;			/* Looping var */
  char		name[1024];		/* Process name */
  const char	*type;			/* Type of program */


  cupsdLogMessage(CUPSD_LOG_DEBUG2, "process_children()");

 /*
  * Reset the dead_children flag...
  */

  dead_children = 0;

 /*
  * Collect the exit status of some children...
  */

#ifdef HAVE_WAITPID
  while ((pid = waitpid(-1, &status, WNOHANG)) > 0)
#elif defined(HAVE_WAIT3)
  while ((pid = wait3(&status, WNOHANG, NULL)) > 0)
#else
  if ((pid = wait(&status)) > 0)
#endif /* HAVE_WAITPID */
  {
   /*
    * Collect the name of the process that finished...
    */

    cupsdFinishProcess(pid, name, sizeof(name), &job_id);

   /*
    * Delete certificates for CGI processes...
    */

    if (pid)
      cupsdDeleteCert(pid);

   /*
    * Handle completed job filters...
    */

    if (job_id > 0)
      job = cupsdFindJob(job_id);
    else
      job  = NULL;

    if (job)
    {
      for (i = 0; job->filters[i]; i ++)
	if (job->filters[i] == pid)
	  break;

      if (job->filters[i] || job->backend == pid)
      {
       /*
	* OK, this process has gone away; what's left?
	*/

	if (job->filters[i])
	{
	  job->filters[i] = -pid;
	  type            = "Filter";
	}
	else
	{
	  job->backend = -pid;
	  type         = "Backend";
	}

	if (status && status != SIGTERM && status != SIGKILL &&
	    status != SIGPIPE)
	{
	 /*
	  * An error occurred; save the exit status so we know to stop
	  * the printer or cancel the job when all of the filters finish...
	  *
	  * A negative status indicates that the backend failed and the
	  * printer needs to be stopped.
	  *
	  * In order to preserve the most serious status, we always log
	  * when a process dies due to a signal (e.g. SIGABRT, SIGSEGV,
	  * and SIGBUS) and prefer to log the backend exit status over a
	  * filter's.
	  */

	  int old_status = abs(job->status);

          if (WIFSIGNALED(status) ||	/* This process crashed, or */
              !job->status ||		/* No process had a status, or */
              (!job->filters[i] && WIFEXITED(old_status)))
          {				/* Backend and filter didn't crash */
	    if (job->filters[i])
	      job->status = status;	/* Filter failed */
	    else
	      job->status = -status;	/* Backend failed */
          }

	  if (job->state_value == IPP_JOB_PROCESSING &&
	      job->status_level > CUPSD_LOG_ERROR &&
	      (job->filters[i] || !WIFEXITED(status)))
	  {
	    char	message[1024];	/* New printer-state-message */


	    job->status_level = CUPSD_LOG_ERROR;

	    snprintf(message, sizeof(message), "%s failed", type);

            if (job->printer)
	    {
	      strlcpy(job->printer->state_message, message,
		       sizeof(job->printer->state_message));
	    }

	    if (!job->attrs)
	      cupsdLoadJob(job);

	    if (!job->printer_message && job->attrs)
	    {
	      if ((job->printer_message =
	               ippFindAttribute(job->attrs, "job-printer-state-message",
					IPP_TAG_TEXT)) == NULL)
		job->printer_message = ippAddString(job->attrs, IPP_TAG_JOB,
		                                    IPP_TAG_TEXT,
						    "job-printer-state-message",
						    NULL, NULL);
	    }

	    if (job->printer_message)
	      cupsdSetString(&(job->printer_message->values[0].string.text),
			     message);
	  }
	}

       /*
	* If this is not the last file in a job, see if all of the
	* filters are done, and if so move to the next file.
	*/

	if (job->current_file < job->num_files && job->printer)
	{
	  for (i = 0; job->filters[i] < 0; i ++);

	  if (!job->filters[i] &&
	      (!job->printer->pc || !job->printer->pc->single_file ||
	       job->backend <= 0))
	  {
	   /*
	    * Process the next file...
	    */

	    cupsdContinueJob(job);
	  }
	}
	else if (job->state_value >= IPP_JOB_CANCELED)
	{
	 /*
	  * Remove the job from the active list if there are no processes still
	  * running for it...
	  */

	  for (i = 0; job->filters[i] < 0; i++);

	  if (!job->filters[i] && job->backend <= 0)
	    cupsArrayRemove(ActiveJobs, job);
	}
      }
    }

   /*
    * Show the exit status as needed, ignoring SIGTERM and SIGKILL errors
    * since they come when we kill/end a process...
    */

    if (status == SIGTERM || status == SIGKILL)
    {
      cupsdLogJob(job, CUPSD_LOG_DEBUG,
		  "PID %d (%s) was terminated normally with signal %d.", pid,
		  name, status);
    }
    else if (status == SIGPIPE)
    {
      cupsdLogJob(job, CUPSD_LOG_DEBUG,
		  "PID %d (%s) did not catch or ignore signal %d.", pid, name,
		  status);
    }
    else if (status)
    {
      if (WIFEXITED(status))
      {
        int code = WEXITSTATUS(status);	/* Exit code */

        if (code > 100)
	  cupsdLogJob(job, CUPSD_LOG_DEBUG,
		      "PID %d (%s) stopped with status %d (%s)", pid, name,
		      code, strerror(code - 100));
	else
	  cupsdLogJob(job, CUPSD_LOG_DEBUG,
		      "PID %d (%s) stopped with status %d.", pid, name, code);
      }
      else
	cupsdLogJob(job, CUPSD_LOG_DEBUG, "PID %d (%s) crashed on signal %d.",
		    pid, name, WTERMSIG(status));

      if (LogLevel < CUPSD_LOG_DEBUG)
        cupsdLogJob(job, CUPSD_LOG_INFO,
		    "Hint: Try setting the LogLevel to \"debug\" to find out "
		    "more.");
    }
    else
      cupsdLogJob(job, CUPSD_LOG_DEBUG, "PID %d (%s) exited with no errors.",
		  pid, name);
  }

 /*
  * If wait*() is interrupted by a signal, tell main() to call us again...
  */

  if (pid < 0 && errno == EINTR)
    dead_children = 1;
}
Exemple #17
0
help_index_t *				/* O - Index pointer or NULL */
helpLoadIndex(const char *hifile,	/* I - Index filename */
              const char *directory)	/* I - Directory that is indexed */
{
  help_index_t	*hi;			/* Help index */
  cups_file_t	*fp;			/* Current file */
  char		line[2048],		/* Line from file */
		*ptr,			/* Pointer into line */
		*filename,		/* Filename in line */
		*anchor,		/* Anchor in line */
		*sectptr,		/* Section pointer in line */
		section[1024],		/* Section name */
		*text;			/* Text in line */
  time_t	mtime;			/* Modification time */
  off_t		offset;			/* Offset into file */
  size_t	length;			/* Length in bytes */
  int		update;			/* Update? */
  help_node_t	*node;			/* Current node */
  help_word_t	*word;			/* Current word */


  DEBUG_printf(("helpLoadIndex(hifile=\"%s\", directory=\"%s\")",
                hifile, directory));

 /*
  * Create a new, empty index.
  */

  if ((hi = (help_index_t *)calloc(1, sizeof(help_index_t))) == NULL)
    return (NULL);

  hi->nodes  = cupsArrayNew((cups_array_func_t)help_sort_by_name, NULL);
  hi->sorted = cupsArrayNew((cups_array_func_t)help_sort_by_score, NULL);

  if (!hi->nodes || !hi->sorted)
  {
    cupsArrayDelete(hi->nodes);
    cupsArrayDelete(hi->sorted);
    free(hi);
    return (NULL);
  }

 /*
  * Try loading the existing index file...
  */

  if ((fp = cupsFileOpen(hifile, "r")) != NULL)
  {
   /*
    * Lock the file and then read the first line...
    */

    cupsFileLock(fp, 1);

    if (cupsFileGets(fp, line, sizeof(line)) && !strcmp(line, "HELPV2"))
    {
     /*
      * Got a valid header line, now read the data lines...
      */

      node = NULL;

      while (cupsFileGets(fp, line, sizeof(line)))
      {
       /*
	* Each line looks like one of the following:
	*
	*     filename mtime offset length "section" "text"
	*     filename#anchor offset length "text"
	*     SP count word
	*/

        if (line[0] == ' ')
	{
	 /*
	  * Read a word in the current node...
	  */

          if (!node || (ptr = strrchr(line, ' ')) == NULL)
	    continue;

          if ((word = help_add_word(node, ptr + 1)) != NULL)
	    word->count = atoi(line + 1);
        }
	else
	{
	 /*
	  * Add a node...
	  */

	  filename = line;

	  if ((ptr = strchr(line, ' ')) == NULL)
            break;

	  while (isspace(*ptr & 255))
            *ptr++ = '\0';

	  if ((anchor = strrchr(filename, '#')) != NULL)
	  {
            *anchor++ = '\0';
	    mtime = 0;
	  }
	  else
	    mtime = strtol(ptr, &ptr, 10);

	  offset = strtoll(ptr, &ptr, 10);
	  length = strtoll(ptr, &ptr, 10);

	  while (isspace(*ptr & 255))
            ptr ++;

          if (!anchor)
	  {
	   /*
	    * Get section...
	    */

            if (*ptr != '\"')
	      break;

            ptr ++;
	    sectptr = ptr;

            while (*ptr && *ptr != '\"')
	      ptr ++;

            if (*ptr != '\"')
	      break;

            *ptr++ = '\0';

            strlcpy(section, sectptr, sizeof(section));

	    while (isspace(*ptr & 255))
              ptr ++;
          }

          if (*ptr != '\"')
	    break;

          ptr ++;
	  text = ptr;

          while (*ptr && *ptr != '\"')
	    ptr ++;

          if (*ptr != '\"')
	    break;

          *ptr++ = '\0';

	  if ((node = help_new_node(filename, anchor, section, text,
				    mtime, offset, length)) == NULL)
            break;

	  node->score = -1;

	  cupsArrayAdd(hi->nodes, node);
        }
      }
    }

    cupsFileClose(fp);
  }

 /*
  * Scan for new/updated files...
  */

  update = help_load_directory(hi, directory, NULL);

 /*
  * Remove any files that are no longer installed...
  */

  for (node = (help_node_t *)cupsArrayFirst(hi->nodes);
       node;
       node = (help_node_t *)cupsArrayNext(hi->nodes))
    if (node->score < 0)
    {
     /*
      * Delete this node...
      */

      cupsArrayRemove(hi->nodes, node);
      help_delete_node(node);
    }

 /*
  * Add nodes to the sorted array...
  */

  for (node = (help_node_t *)cupsArrayFirst(hi->nodes);
       node;
       node = (help_node_t *)cupsArrayNext(hi->nodes))
    cupsArrayAdd(hi->sorted, node);

 /*
  * Save the index if we updated it...
  */

  if (update)
    helpSaveIndex(hi, hifile);

 /*
  * Return the index...
  */

  return (hi);
}
static int				/* O - 0 on success, 1 on error */
exec_filters(cups_array_t  *filters,	/* I - Array of filters to run */
	     char	   **argv)	/* I - Filter options */
{
  int		i;			/* Looping var */
  char		program[1024];		/* Program to run */
  char		*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 */
  filter_pid_t	*pid_entry,		/* Entry in executed filters array */
		key;			/* Search key for filters */
  const char	*cups_serverbin;	/* CUPS_SERVERBIN environment variable */

 /*
  * Remove NULL ("-") filters...
  */

  for (filter = (char *)cupsArrayFirst(filters);
       filter;
       filter = (char *)cupsArrayNext(filters))
    if (!strcmp(filter, "-"))
      cupsArrayRemove(filters, filter);

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

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

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

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

    if (filter[0] == '/')
      strncpy(program, filter, sizeof(program));
    else
    {
      if ((cups_serverbin = getenv("CUPS_SERVERBIN")) == NULL)
	cups_serverbin = CUPS_SERVERBIN;
      snprintf(program, sizeof(program), "%s/filter/%s", cups_serverbin,
	       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
      filterfds[1 - current][1] = 1;

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

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

      pid_entry = malloc(sizeof(filter_pid_t));
      pid_entry->pid = pid;
      pid_entry->name = filter;
      cupsArrayAdd(pids, pid_entry);
    }
    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)
    {
      if (errno == EINTR && job_canceled)
      {
	fprintf(stderr, "DEBUG: Job canceled, killing filters ...\n");
	for (pid_entry = (filter_pid_t *)cupsArrayFirst(pids);
	     pid_entry;
	     pid_entry = (filter_pid_t *)cupsArrayNext(pids))
	  kill(pid_entry->pid, SIGTERM);
	job_canceled = 0;
      }
      else
	continue;
    }

    key.pid = pid;
    if ((pid_entry = (filter_pid_t *)cupsArrayFind(pids, &key)) != NULL)
    {
      cupsArrayRemove(pids, pid_entry);

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

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

      free(pid_entry);
    }
  }

  cupsArrayDelete(pids);

  return (retval);
}
static void
ppd_handle_media(ppd_file_t *ppd)	/* I - PPD file */
{
  ppd_choice_t	*manual_feed,		/* ManualFeed choice, if any */
		*input_slot;		/* InputSlot choice, if any */
  ppd_size_t	*size;			/* Current media size */
  ppd_attr_t	*rpr;			/* RequiresPageRegion value */


 /*
  * This function determines what page size code to use, if any, for the
  * current media size, InputSlot, and ManualFeed selections.
  *
  * We use the PageSize code if:
  *
  * 1. A custom media size is selected.
  * 2. ManualFeed and InputSlot are not selected (or do not exist).
  * 3. ManualFeed is selected but is False and InputSlot is not selected or
  *    the selection has no code - the latter check done to support "auto" or
  *    "printer default" InputSlot options.
  *
  * We use the PageRegion code if:
  *
  * 4. RequiresPageRegion does not exist and the PPD contains cupsFilter
  *    keywords, indicating this is a CUPS-based driver.
  * 5. RequiresPageRegion exists for the selected InputSlot (or "All" for any
  *    InputSlot or ManualFeed selection) and is True.
  *
  * If none of the 5 conditions are true, no page size code is used and we
  * unmark any existing PageSize or PageRegion choices.
  */

  if ((size = ppdPageSize(ppd, NULL)) == NULL)
    return;

  manual_feed = ppdFindMarkedChoice(ppd, "ManualFeed");
  input_slot  = ppdFindMarkedChoice(ppd, "InputSlot");

  if (input_slot != NULL)
    rpr = ppdFindAttr(ppd, "RequiresPageRegion", input_slot->choice);
  else
    rpr = NULL;

  if (!rpr)
    rpr = ppdFindAttr(ppd, "RequiresPageRegion", "All");

  if (!_cups_strcasecmp(size->name, "Custom") ||
      (!manual_feed && !input_slot) ||
      (manual_feed && !_cups_strcasecmp(manual_feed->choice, "False") &&
       (!input_slot || (input_slot->code && !input_slot->code[0]))) ||
      (!rpr && ppd->num_filters > 0))
  {
   /*
    * Use PageSize code...
    */

    ppdMarkOption(ppd, "PageSize", size->name);
  }
  else if (rpr && rpr->value && !_cups_strcasecmp(rpr->value, "True"))
  {
   /*
    * Use PageRegion code...
    */

    ppdMarkOption(ppd, "PageRegion", size->name);
  }
  else
  {
   /*
    * Do not use PageSize or PageRegion code...
    */

    ppd_choice_t	*page;		/* PageSize/Region choice, if any */

    if ((page = ppdFindMarkedChoice(ppd, "PageSize")) != NULL)
    {
     /*
      * Unmark PageSize...
      */

      page->marked = 0;
      cupsArrayRemove(ppd->marked, page);
    }

    if ((page = ppdFindMarkedChoice(ppd, "PageRegion")) != NULL)
    {
     /*
      * Unmark PageRegion...
      */

      page->marked = 0;
      cupsArrayRemove(ppd->marked, page);
    }
  }
}
Exemple #20
0
void
_cupsStrFree(const char *s)		/* I - String to free */
{
  _cups_sp_item_t	*item,		/* String pool item */
			key;		/* Search key */


 /*
  * Range check input...
  */

  if (!s)
    return;

 /*
  * Check the string pool...
  *
  * We don't need to lock the mutex yet, as we only want to know if
  * the stringpool is initialized.  The rest of the code will still
  * work if it is initialized before we lock...
  */

  if (!stringpool)
    return;

 /*
  * See if the string is already in the pool...
  */

#ifdef HAVE_PTHREAD_H
  pthread_mutex_lock(&sp_mutex);
#endif /* HAVE_PTHREAD_H */

  key.str = (char *)s;

  if ((item = (_cups_sp_item_t *)cupsArrayFind(stringpool, &key)) != NULL &&
      item->str == s)
  {
   /*
    * Found it, dereference...
    */

    item->ref_count --;

    if (!item->ref_count)
    {
     /*
      * Remove and free...
      */

      cupsArrayRemove(stringpool, item);

      free(item->str);
      free(item);
    }
  }

#ifdef HAVE_PTHREAD_H
  pthread_mutex_unlock(&sp_mutex);
#endif /* HAVE_PTHREAD_H */
}
Exemple #21
0
static int				/* O - 0 = success, -1 = error */
help_load_file(
    help_index_t *hi,			/* I - Index */
    const char   *filename,		/* I - Filename */
    const char   *relative,		/* I - Relative path */
    time_t       mtime)			/* I - Modification time */
{
  cups_file_t	*fp;			/* HTML file */
  help_node_t	*node;			/* Current node */
  char		line[1024],		/* Line from file */
		temp[1024],		/* Temporary word */
                section[1024],		/* Section */
		*ptr,			/* Pointer into line */
		*anchor,		/* Anchor name */
		*text;			/* Text for anchor */
  off_t		offset;			/* File offset */
  char		quote;			/* Quote character */
  help_word_t	*word;			/* Current word */
  int		wordlen;		/* Length of word */


  DEBUG_printf(("2help_load_file(hi=%p, filename=\"%s\", relative=\"%s\", "
                "mtime=%ld)", hi, filename, relative, mtime));

  if ((fp = cupsFileOpen(filename, "r")) == NULL)
    return (-1);

  node   = NULL;
  offset = 0;

  strlcpy(section, "Other", sizeof(section));

  while (cupsFileGets(fp, line, sizeof(line)))
  {
   /*
    * Look for "<TITLE>", "<A NAME", or "<!-- SECTION:" prefix...
    */

    if (!_cups_strncasecmp(line, "<!-- SECTION:", 13))
    {
     /*
      * Got section line, copy it!
      */

      for (ptr = line + 13; isspace(*ptr & 255); ptr ++);

      strlcpy(section, ptr, sizeof(section));
      if ((ptr = strstr(section, "-->")) != NULL)
      {
       /*
        * Strip comment stuff from end of line...
	*/

        for (*ptr-- = '\0'; ptr > line && isspace(*ptr & 255); *ptr-- = '\0');

	if (isspace(*ptr & 255))
	  *ptr = '\0';
      }
      continue;
    }

    for (ptr = line; (ptr = strchr(ptr, '<')) != NULL;)
    {
      ptr ++;

      if (!_cups_strncasecmp(ptr, "TITLE>", 6))
      {
       /*
        * Found the title...
	*/

	anchor = NULL;
	ptr += 6;
      }
      else if (!_cups_strncasecmp(ptr, "A NAME=", 7))
      {
       /*
        * Found an anchor...
	*/

        ptr += 7;

	if (*ptr == '\"' || *ptr == '\'')
	{
	 /*
	  * Get quoted anchor...
	  */

	  quote  = *ptr;
          anchor = ptr + 1;
	  if ((ptr = strchr(anchor, quote)) != NULL)
	    *ptr++ = '\0';
	  else
	    break;
	}
	else
	{
	 /*
	  * Get unquoted anchor...
	  */

          anchor = ptr + 1;

	  for (ptr = anchor; *ptr && *ptr != '>' && !isspace(*ptr & 255); ptr ++);

	  if (*ptr)
	    *ptr++ = '\0';
	  else
	    break;
	}

       /*
        * Got the anchor, now lets find the end...
	*/

        while (*ptr && *ptr != '>')
	  ptr ++;

        if (*ptr != '>')
	  break;

        ptr ++;
      }
      else
        continue;

     /*
      * Now collect text for the link...
      */

      text = ptr;
      while ((ptr = strchr(text, '<')) == NULL)
      {
	ptr = text + strlen(text);
	if (ptr >= (line + sizeof(line) - 2))
	  break;

        *ptr++ = ' ';

        if (!cupsFileGets(fp, ptr, sizeof(line) - (ptr - line) - 1))
	  break;
      }

      *ptr = '\0';

      if (node)
	node->length = offset - node->offset;

      if (!*text)
      {
        node = NULL;
        break;
      }

      if ((node = helpFindNode(hi, relative, anchor)) != NULL)
      {
       /*
	* Node already in the index, so replace the text and other
	* data...
	*/

        cupsArrayRemove(hi->nodes, node);

        if (node->section)
	  free(node->section);

	if (node->text)
	  free(node->text);

        if (node->words)
	{
	  for (word = (help_word_t *)cupsArrayFirst(node->words);
	       word;
	       word = (help_word_t *)cupsArrayNext(node->words))
	    help_delete_word(word);

	  cupsArrayDelete(node->words);
	  node->words = NULL;
	}

	node->section = section[0] ? strdup(section) : NULL;
	node->text    = strdup(text);
	node->mtime   = mtime;
	node->offset  = offset;
	node->score   = 0;
      }
      else
      {
       /*
	* New node...
	*/

        node = help_new_node(relative, anchor, section, text, mtime, offset, 0);
      }

     /*
      * Go through the text value and replace tabs and newlines with
      * whitespace and eliminate extra whitespace...
      */

      for (ptr = node->text, text = node->text; *ptr;)
	if (isspace(*ptr & 255))
	{
	  while (isspace(*ptr & 255))
	    ptr ++;

	  *text++ = ' ';
        }
	else if (text != ptr)
	  *text++ = *ptr++;
	else
	{
	  text ++;
	  ptr ++;
	}

      *text = '\0';

     /*
      * (Re)add the node to the array...
      */

      cupsArrayAdd(hi->nodes, node);

      if (!anchor)
        node = NULL;
      break;
    }

    if (node)
    {
     /*
      * Scan this line for words...
      */

      for (ptr = line; *ptr; ptr ++)
      {
       /*
	* Skip HTML stuff...
	*/

	if (*ptr == '<')
	{
          if (!strncmp(ptr, "<!--", 4))
	  {
	   /*
	    * Skip HTML comment...
	    */

            if ((text = strstr(ptr + 4, "-->")) == NULL)
	      ptr += strlen(ptr) - 1;
	    else
	      ptr = text + 2;
	  }
	  else
	  {
	   /*
            * Skip HTML element...
	    */

            for (ptr ++; *ptr && *ptr != '>'; ptr ++)
	    {
	      if (*ptr == '\"' || *ptr == '\'')
	      {
		for (quote = *ptr++; *ptr && *ptr != quote; ptr ++);

		if (!*ptr)
		  ptr --;
	      }
	    }

	    if (!*ptr)
	      ptr --;
          }

          continue;
	}
	else if (*ptr == '&')
	{
	 /*
	  * Skip HTML entity...
	  */

	  for (ptr ++; *ptr && *ptr != ';'; ptr ++);

	  if (!*ptr)
	    ptr --;

	  continue;
	}
	else if (!isalnum(*ptr & 255))
          continue;

       /*
	* Found the start of a word, search until we find the end...
	*/

	for (text = ptr, ptr ++; *ptr && isalnum(*ptr & 255); ptr ++);

	wordlen = ptr - text;

        memcpy(temp, text, wordlen);
	temp[wordlen] = '\0';

        ptr --;

	if (wordlen > 1 && !bsearch(temp, help_common_words,
	                            (sizeof(help_common_words) /
				     sizeof(help_common_words[0])),
				    sizeof(help_common_words[0]),
				    (int (*)(const void *, const void *))
				        _cups_strcasecmp))
          help_add_word(node, temp);
      }
    }

   /*
    * Get the offset of the next line...
    */

    offset = cupsFileTell(fp);
  }

  cupsFileClose(fp);

  if (node)
    node->length = offset - node->offset;

  return (0);
}
Exemple #22
0
void
_cupsStrFree(const char *s)		/* I - String to free */
{
  _cups_sp_item_t	*item,		/* String pool item */
			*key;		/* Search key */


 /*
  * Range check input...
  */

  if (!s)
    return;

 /*
  * Check the string pool...
  *
  * We don't need to lock the mutex yet, as we only want to know if
  * the stringpool is initialized.  The rest of the code will still
  * work if it is initialized before we lock...
  */

  if (!stringpool)
    return;

 /*
  * See if the string is already in the pool...
  */

  _cupsMutexLock(&sp_mutex);

  key = (_cups_sp_item_t *)(s - offsetof(_cups_sp_item_t, str));

#ifdef DEBUG_GUARDS
  if (key->guard != _CUPS_STR_GUARD)
  {
    DEBUG_printf(("5_cupsStrFree: Freeing string %p(%s), guard=%08x, "
                  "ref_count=%d", key, key->str, key->guard, key->ref_count));
    abort();
  }
#endif /* DEBUG_GUARDS */

  if ((item = (_cups_sp_item_t *)cupsArrayFind(stringpool, key)) != NULL &&
      item == key)
  {
   /*
    * Found it, dereference...
    */

    item->ref_count --;

    if (!item->ref_count)
    {
     /*
      * Remove and free...
      */

      cupsArrayRemove(stringpool, item);

      free(item);
    }
  }

  _cupsMutexUnlock(&sp_mutex);
}
Exemple #23
0
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 ++;
}
Exemple #24
0
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);
}