Пример #1
0
static int				/* O - 1 if form data was read */
cgi_initialize_multipart(
    const char *boundary)		/* I - Boundary string */
{
  char		line[10240],		/* MIME header line */
		name[1024],		/* Form variable name */
		filename[1024],		/* Form filename */
		mimetype[1024],		/* MIME media type */
		bstring[256],		/* Boundary string to look for */
		*ptr,			/* Pointer into name/filename */
		*end;			/* End of buffer */
  int		ch,			/* Character from file */
		fd;			/* Temporary file descriptor */
  size_t	blen;			/* Length of boundary string */


  DEBUG_printf(("cgi_initialize_multipart(boundary=\"%s\")\n", boundary));

 /*
  * Read multipart form data until we run out...
  */

  name[0]     = '\0';
  filename[0] = '\0';
  mimetype[0] = '\0';

  snprintf(bstring, sizeof(bstring), "\r\n--%s", boundary);
  blen = strlen(bstring);

  while (fgets(line, sizeof(line), stdin))
  {
    if (!strcmp(line, "\r\n"))
    {
     /*
      * End of headers, grab value...
      */

      if (filename[0])
      {
       /*
        * Read an embedded file...
	*/

        if (form_file)
	{
	 /*
	  * Remove previous file...
	  */

	  cgi_unlink_file();
	}

       /*
        * Allocate memory for the new file...
	*/

	if ((form_file = calloc(1, sizeof(cgi_file_t))) == NULL)
	  return (0);

        form_file->name     = strdup(name);
	form_file->filename = strdup(filename);
	form_file->mimetype = strdup(mimetype);

        fd = cupsTempFd(form_file->tempfile, sizeof(form_file->tempfile));

        if (fd < 0)
	  return (0);

        atexit(cgi_unlink_file);

       /*
        * Copy file data to the temp file...
	*/

        ptr = line;

	while ((ch = getchar()) != EOF)
	{
	  *ptr++ = (char)ch;

          if ((size_t)(ptr - line) >= blen && !memcmp(ptr - blen, bstring, blen))
	  {
	    ptr -= blen;
	    break;
	  }

          if ((ptr - line - (int)blen) >= 8192)
	  {
	   /*
	    * Write out the first 8k of the buffer...
	    */

	    write(fd, line, 8192);
	    memmove(line, line + 8192, (size_t)(ptr - line - 8192));
	    ptr -= 8192;
	  }
	}

       /*
        * Write the rest of the data and close the temp file...
	*/

	if (ptr > line)
          write(fd, line, (size_t)(ptr - line));

	close(fd);
      }
      else
      {
       /*
        * Just get a form variable; the current code only handles
	* form values up to 10k in size...
	*/

        ptr = line;
	end = line + sizeof(line) - 1;

	while ((ch = getchar()) != EOF)
	{
	  if (ptr < end)
	    *ptr++ = (char)ch;

          if ((size_t)(ptr - line) >= blen && !memcmp(ptr - blen, bstring, blen))
	  {
	    ptr -= blen;
	    break;
	  }
	}

	*ptr = '\0';

       /*
        * Set the form variable...
	*/

	if ((ptr = strrchr(name, '-')) != NULL && isdigit(ptr[1] & 255))
	{
	 /*
	  * Set a specific index in the array...
	  */

	  *ptr++ = '\0';
	  if (line[0])
            cgiSetArray(name, atoi(ptr) - 1, line);
	}
	else if (cgiGetVariable(name))
	{
	 /*
	  * Add another element in the array...
	  */

	  cgiSetArray(name, cgiGetSize(name), line);
	}
	else
	{
	 /*
	  * Just set the line...
	  */

	  cgiSetVariable(name, line);
	}
      }

     /*
      * Read the rest of the current line...
      */

      fgets(line, sizeof(line), stdin);

     /*
      * Clear the state vars...
      */

      name[0]     = '\0';
      filename[0] = '\0';
      mimetype[0] = '\0';
    }
    else if (!_cups_strncasecmp(line, "Content-Disposition:", 20))
    {
      if ((ptr = strstr(line + 20, " name=\"")) != NULL)
      {
        strlcpy(name, ptr + 7, sizeof(name));

	if ((ptr = strchr(name, '\"')) != NULL)
	  *ptr = '\0';
      }

      if ((ptr = strstr(line + 20, " filename=\"")) != NULL)
      {
        strlcpy(filename, ptr + 11, sizeof(filename));

	if ((ptr = strchr(filename, '\"')) != NULL)
	  *ptr = '\0';
      }
    }
    else if (!_cups_strncasecmp(line, "Content-Type:", 13))
    {
      for (ptr = line + 13; isspace(*ptr & 255); ptr ++);

      strlcpy(mimetype, ptr, sizeof(mimetype));

      for (ptr = mimetype + strlen(mimetype) - 1;
           ptr > mimetype && isspace(*ptr & 255);
	   *ptr-- = '\0');
    }
  }

 /*
  * Return 1 for "form data found"...
  */

  return (1);
}
Пример #2
0
void
cgiMoveJobs(http_t     *http,		/* I - Connection to server */
            const char *dest,		/* I - Destination or NULL */
            int        job_id)		/* I - Job ID or 0 for all */
{
  int		i;			/* Looping var */
  const char	*user;			/* Username */
  ipp_t		*request,		/* IPP request */
		*response;		/* IPP response */
  ipp_attribute_t *attr;		/* Current attribute */
  const char	*name;			/* Destination name */
  const char	*job_printer_uri;	/* JOB_PRINTER_URI form variable */
  char		current_dest[1024];	/* Current destination */


 /*
  * Make sure we have a username...
  */

  if ((user = getenv("REMOTE_USER")) == NULL)
  {
    puts("Status: 401\n");
    exit(0);
  }

 /*
  * See if the user has already selected a new destination...
  */

  if ((job_printer_uri = cgiGetVariable("JOB_PRINTER_URI")) == NULL)
  {
   /*
    * Make sure necessary form variables are set...
    */

    if (job_id)
    {
      char	temp[255];		/* Temporary string */


      sprintf(temp, "%d", job_id);
      cgiSetVariable("JOB_ID", temp);
    }

    if (dest)
      cgiSetVariable("PRINTER_NAME", dest);

   /*
    * No new destination specified, show the user what the available
    * printers/classes are...
    */

    if (!dest)
    {
     /*
      * Get the current destination for job N...
      */

      char	job_uri[1024];		/* Job URI */


      request = ippNewRequest(IPP_GET_JOB_ATTRIBUTES);

      snprintf(job_uri, sizeof(job_uri), "ipp://localhost/jobs/%d", job_id);
      ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "job-uri",
                   NULL, job_uri);
      ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
                   "requested-attributes", NULL, "job-printer-uri");

      if ((response = cupsDoRequest(http, request, "/")) != NULL)
      {
        if ((attr = ippFindAttribute(response, "job-printer-uri",
	                             IPP_TAG_URI)) != NULL)
	{
	 /*
	  * Pull the name from the URI...
	  */

	  strlcpy(current_dest, strrchr(attr->values[0].string.text, '/') + 1,
	          sizeof(current_dest));
          dest = current_dest;
	}

        ippDelete(response);
      }

      if (!dest)
      {
       /*
        * Couldn't get the current destination...
	*/

        cgiStartHTML(cgiText(_("Move Job")));
	cgiShowIPPError(_("Unable to find destination for job"));
	cgiEndHTML();
	return;
      }
    }

   /*
    * Get the list of available destinations...
    */

    request = ippNewRequest(CUPS_GET_PRINTERS);

    ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
                 "requested-attributes", NULL, "printer-uri-supported");

    if (user)
      ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
		   "requesting-user-name", NULL, user);

    ippAddInteger(request, IPP_TAG_OPERATION, IPP_TAG_ENUM, "printer-type",
                  CUPS_PRINTER_LOCAL);
    ippAddInteger(request, IPP_TAG_OPERATION, IPP_TAG_ENUM, "printer-type-mask",
                  CUPS_PRINTER_SCANNER);

    if ((response = cupsDoRequest(http, request, "/")) != NULL)
    {
      for (i = 0, attr = ippFindAttribute(response, "printer-uri-supported",
                                          IPP_TAG_URI);
           attr;
	   attr = ippFindNextAttribute(response, "printer-uri-supported",
	                               IPP_TAG_URI))
      {
       /*
	* Pull the name from the URI...
	*/

	name = strrchr(attr->values[0].string.text, '/') + 1;

       /*
        * If the name is not the same as the current destination, add it!
	*/

        if (_cups_strcasecmp(name, dest))
	{
	  cgiSetArray("JOB_PRINTER_URI", i, attr->values[0].string.text);
	  cgiSetArray("JOB_PRINTER_NAME", i, name);
	  i ++;
	}
      }

      ippDelete(response);
    }

   /*
    * Show the form...
    */

    if (job_id)
      cgiStartHTML(cgiText(_("Move Job")));
    else
      cgiStartHTML(cgiText(_("Move All Jobs")));

    if (cgiGetSize("JOB_PRINTER_NAME") > 0)
      cgiCopyTemplateLang("job-move.tmpl");
    else
    {
      if (job_id)
	cgiSetVariable("MESSAGE", cgiText(_("Unable to move job")));
      else
	cgiSetVariable("MESSAGE", cgiText(_("Unable to move jobs")));

      cgiSetVariable("ERROR", cgiText(_("No destinations added.")));
      cgiCopyTemplateLang("error.tmpl");
    }
  }
  else
  {
   /*
    * Try moving the job or jobs...
    */

    char	uri[1024],		/* Job/printer URI */
		resource[1024],		/* Post resource */
		refresh[1024];		/* Refresh URL */
    const char	*job_printer_name;	/* New printer name */


    request = ippNewRequest(CUPS_MOVE_JOB);

    if (job_id)
    {
     /*
      * Move 1 job...
      */

      snprintf(resource, sizeof(resource), "/jobs/%d", job_id);

      snprintf(uri, sizeof(uri), "ipp://localhost/jobs/%d", job_id);
      ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "job-uri",
                   NULL, uri);
    }
    else
    {
     /*
      * Move all active jobs on a destination...
      */

      snprintf(resource, sizeof(resource), "/%s/%s",
               cgiGetVariable("SECTION"), dest);

      httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
                       "localhost", ippPort(), "/%s/%s",
		       cgiGetVariable("SECTION"), dest);
      ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
                   NULL, uri);
    }

    ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "job-printer-uri",
                 NULL, job_printer_uri);

    ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
                 "requesting-user-name", NULL, user);

    ippDelete(cupsDoRequest(http, request, resource));

   /*
    * Show the results...
    */

    job_printer_name = strrchr(job_printer_uri, '/') + 1;

    if (cupsLastError() <= IPP_OK_CONFLICT)
    {
      const char *path = strstr(job_printer_uri, "/printers/");
      if (!path)
      {
        path = strstr(job_printer_uri, "/classes/");
        cgiSetVariable("IS_CLASS", "YES");
      }

      if (path)
      {
        cgiFormEncode(uri, path, sizeof(uri));
        snprintf(refresh, sizeof(refresh), "2;URL=%s", uri);
	cgiSetVariable("refresh_page", refresh);
      }
    }

    if (job_id)
      cgiStartHTML(cgiText(_("Move Job")));
    else
      cgiStartHTML(cgiText(_("Move All Jobs")));

    if (cupsLastError() > IPP_OK_CONFLICT)
    {
      if (job_id)
	cgiShowIPPError(_("Unable to move job"));
      else
        cgiShowIPPError(_("Unable to move jobs"));
    }
    else
    {
      cgiSetVariable("JOB_PRINTER_NAME", job_printer_name);
      cgiCopyTemplateLang("job-moved.tmpl");
    }
  }

  cgiEndHTML();
}
Пример #3
0
static int				/* O - 1 if form data was processed */
cgi_initialize_string(const char *data)	/* I - Form data string */
{
  int	done;				/* True if we're done reading a form variable */
  char	*s,				/* Pointer to current form string */
	ch,				/* Temporary character */
	name[255],			/* Name of form variable */
	value[65536];			/* Variable value */


 /*
  * Check input...
  */

  if (data == NULL)
    return (0);

 /*
  * Loop until we've read all the form data...
  */

  while (*data != '\0')
  {
   /*
    * Get the variable name...
    */

    for (s = name; *data != '\0'; data ++)
      if (*data == '=')
        break;
      else if (*data >= ' ' && s < (name + sizeof(name) - 1))
        *s++ = *data;

    *s = '\0';
    if (*data == '=')
      data ++;
    else
      return (0);

   /*
    * Read the variable value...
    */

    for (s = value, done = 0; !done && *data != '\0'; data ++)
      switch (*data)
      {
	case '&' :	/* End of data... */
            done = 1;
            break;

	case '+' :	/* Escaped space character */
            if (s < (value + sizeof(value) - 1))
              *s++ = ' ';
            break;

	case '%' :	/* Escaped control character */
	   /*
	    * Read the hex code...
	    */

            if (!isxdigit(data[1] & 255) || !isxdigit(data[2] & 255))
	      return (0);

            if (s < (value + sizeof(value) - 1))
	    {
              data ++;
              ch = *data - '0';
              if (ch > 9)
        	ch -= 7;
              *s = (char)(ch << 4);

              data ++;
              ch = *data - '0';
              if (ch > 9)
        	ch -= 7;
              *s++ |= ch;
            }
	    else
	      data += 2;
            break;

	default :	/* Other characters come straight through */
	    if (*data >= ' ' && s < (value + sizeof(value) - 1))
              *s++ = *data;
            break;
      }

    *s = '\0';		/* nul terminate the string */

   /*
    * Remove trailing whitespace...
    */

    if (s > value)
      s --;

    while (s >= value && isspace(*s & 255))
      *s-- = '\0';

   /*
    * Add the string to the variable "database"...
    */

    if ((s = strrchr(name, '-')) != NULL && isdigit(s[1] & 255))
    {
      *s++ = '\0';
      if (value[0])
        cgiSetArray(name, atoi(s) - 1, value);
    }
    else if (cgiGetVariable(name) != NULL)
      cgiSetArray(name, cgiGetSize(name), value);
    else
      cgiSetVariable(name, value);
  }

  return (1);
}
Пример #4
0
static void
cgi_copy(FILE *out,			/* I - Output file */
         FILE *in,			/* I - Input file */
	 int  element,			/* I - Element number (0 to N) */
	 char term,			/* I - Terminating character */
	 int  indent)			/* I - Debug info indentation */
{
  int		ch;			/* Character from file */
  char		op;			/* Operation */
  char		name[255],		/* Name of variable */
		*nameptr,		/* Pointer into name */
		innername[255],		/* Inner comparison name */
		*innerptr,		/* Pointer into inner name */
		*s;			/* String pointer */
  const char	*value;			/* Value of variable */
  const char	*innerval;		/* Inner value */
  const char	*outptr;		/* Output string pointer */
  char		outval[1024],		/* Formatted output string */
		compare[1024];		/* Comparison string */
  int		result;			/* Result of comparison */
  int		uriencode;		/* Encode as URI */
  regex_t	re;			/* Regular expression to match */


  fprintf(stderr, "DEBUG2: %*sStarting at file position %ld...\n", indent, "",
          ftell(in));

 /*
  * Parse the file to the end...
  */

  while ((ch = getc(in)) != EOF)
    if (ch == term)
      break;
    else if (ch == '{')
    {
     /*
      * Get a variable name...
      */

      uriencode = 0;

      for (s = name; (ch = getc(in)) != EOF;)
        if (strchr("}]<>=!~ \t\n", ch))
          break;
	else if (s == name && ch == '%')
	  uriencode = 1;
        else if (s > name && ch == '?')
	  break;
	else if (s < (name + sizeof(name) - 1))
          *s++ = ch;

      *s = '\0';

      if (s == name && isspace(ch & 255))
      {
        fprintf(stderr, "DEBUG2: %*sLone { at %ld...\n", indent, "", ftell(in));

        if (out)
	{
          putc('{', out);
	  putc(ch, out);
        }

	continue;
      }

      if (ch == '}')
	fprintf(stderr, "DEBUG2: %*s\"{%s}\" at %ld...\n", indent, "", name,
        	ftell(in));

     /*
      * See if it has a value...
      */

      if (name[0] == '?')
      {
       /*
        * Insert value only if it exists...
	*/

	if ((nameptr = strrchr(name, '-')) != NULL && isdigit(nameptr[1] & 255))
	{
	  *nameptr++ = '\0';

	  if ((value = cgiGetArray(name + 1, atoi(nameptr) - 1)) != NULL)
	    outptr = value;
	  else
	  {
	    outval[0] = '\0';
	    outptr    = outval;
	  }
	}
        else if ((value = cgiGetArray(name + 1, element)) != NULL)
	  outptr = value;
	else
	{
	  outval[0] = '\0';
	  outptr    = outval;
	}
      }
      else if (name[0] == '#')
      {
       /*
        * Insert count...
	*/

        if (name[1])
          sprintf(outval, "%d", cgiGetSize(name + 1));
	else
	  sprintf(outval, "%d", element + 1);

        outptr = outval;
      }
      else if (name[0] == '[')
      {
       /*
        * Loop for # of elements...
	*/

	int  i;		/* Looping var */
        long pos;	/* File position */
	int  count;	/* Number of elements */


        if (isdigit(name[1] & 255))
	  count = atoi(name + 1);
	else
          count = cgiGetSize(name + 1);

	pos = ftell(in);

        fprintf(stderr, "DEBUG2: %*sLooping on \"%s\" at %ld, count=%d...\n",
	        indent, "", name + 1, pos, count);

        if (count > 0)
	{
          for (i = 0; i < count; i ++)
	  {
	    if (i)
	      fseek(in, pos, SEEK_SET);

	    cgi_copy(out, in, i, '}', indent + 2);
	  }
        }
	else
	  cgi_copy(NULL, in, 0, '}', indent + 2);

        fprintf(stderr, "DEBUG2: %*sFinished looping on \"%s\"...\n", indent,
	        "", name + 1);

        continue;
      }
      else if (name[0] == '$')
      {
       /*
        * Insert cookie value or nothing if not defined.
	*/

        if ((value = cgiGetCookie(name + 1)) != NULL)
	  outptr = value;
	else
	{
	  outval[0] = '\0';
	  outptr    = outval;
	}
      }
      else
      {
       /*
        * Insert variable or variable name (if element is NULL)...
	*/

	if ((nameptr = strrchr(name, '-')) != NULL && isdigit(nameptr[1] & 255))
	{
	  *nameptr++ = '\0';
	  if ((value = cgiGetArray(name, atoi(nameptr) - 1)) == NULL)
          {
	    snprintf(outval, sizeof(outval), "{%s}", name);
	    outptr = outval;
	  }
	  else
	    outptr = value;
	}
	else if ((value = cgiGetArray(name, element)) == NULL)
        {
	  snprintf(outval, sizeof(outval), "{%s}", name);
	  outptr = outval;
	}
	else
	  outptr = value;
      }

     /*
      * See if the terminating character requires another test...
      */

      if (ch == '}')
      {
       /*
        * End of substitution...
        */

	if (out)
	{
	  if (uriencode)
	    cgi_puturi(outptr, out);
	  else if (!_cups_strcasecmp(name, "?cupsdconf_default"))
	    fputs(outptr, stdout);
	  else
	    cgi_puts(outptr, out);
        }

        continue;
      }

     /*
      * OK, process one of the following checks:
      *
      *   {name?exist:not-exist}     Exists?
      *   {name=value?true:false}    Equal
      *   {name<value?true:false}    Less than
      *   {name>value?true:false}    Greater than
      *   {name!value?true:false}    Not equal
      *   {name~refex?true:false}    Regex match
      */

      op = ch;

      if (ch == '?')
      {
       /*
        * Test for existance...
	*/

        if (name[0] == '?')
	  result = cgiGetArray(name + 1, element) != NULL;
	else if (name[0] == '#')
	  result = cgiGetVariable(name + 1) != NULL;
        else
          result = cgiGetArray(name, element) != NULL;

	result     = result && outptr[0];
	compare[0] = '\0';
      }
      else
      {
       /*
        * Compare to a string...
	*/

	for (s = compare; (ch = getc(in)) != EOF;)
          if (ch == '?')
            break;
	  else if (s >= (compare + sizeof(compare) - 1))
	    continue;
	  else if (ch == '#')
	  {
	    sprintf(s, "%d", element + 1);
	    s += strlen(s);
	  }
	  else if (ch == '{')
	  {
	   /*
	    * Grab the value of a variable...
	    */

	    innerptr = innername;
	    while ((ch = getc(in)) != EOF && ch != '}')
	      if (innerptr < (innername + sizeof(innername) - 1))
	        *innerptr++ = ch;
	    *innerptr = '\0';

            if (innername[0] == '#')
	      sprintf(s, "%d", cgiGetSize(innername + 1));
	    else if ((innerptr = strrchr(innername, '-')) != NULL &&
	             isdigit(innerptr[1] & 255))
            {
	      *innerptr++ = '\0';
	      if ((innerval = cgiGetArray(innername, atoi(innerptr) - 1)) == NULL)
	        *s = '\0';
	      else
	        strlcpy(s, innerval, sizeof(compare) - (s - compare));
	    }
	    else if (innername[0] == '?')
	    {
	      if ((innerval = cgiGetArray(innername + 1, element)) == NULL)
		*s = '\0';
	      else
	        strlcpy(s, innerval, sizeof(compare) - (s - compare));
            }
	    else if ((innerval = cgiGetArray(innername, element)) == NULL)
	      snprintf(s, sizeof(compare) - (s - compare), "{%s}", innername);
	    else
	      strlcpy(s, innerval, sizeof(compare) - (s - compare));

            s += strlen(s);
	  }
          else if (ch == '\\')
	    *s++ = getc(in);
	  else
            *s++ = ch;

        *s = '\0';

        if (ch != '?')
	{
	  fprintf(stderr,
	          "DEBUG2: %*sBad terminator '%c' at file position %ld...\n",
	          indent, "", ch, ftell(in));
	  return;
	}

       /*
        * Do the comparison...
	*/

        switch (op)
	{
	  case '<' :
	      result = _cups_strcasecmp(outptr, compare) < 0;
	      break;
	  case '>' :
	      result = _cups_strcasecmp(outptr, compare) > 0;
	      break;
	  case '=' :
	      result = _cups_strcasecmp(outptr, compare) == 0;
	      break;
	  case '!' :
	      result = _cups_strcasecmp(outptr, compare) != 0;
	      break;
	  case '~' :
	      fprintf(stderr, "DEBUG: Regular expression \"%s\"\n", compare);

	      if (regcomp(&re, compare, REG_EXTENDED | REG_ICASE))
	      {
	        fprintf(stderr,
		        "ERROR: Unable to compile regular expresion \"%s\"!\n",
			compare);
		result = 0;
	      }
	      else
	      {
	        regmatch_t matches[10];

		result = 0;

	        if (!regexec(&re, outptr, 10, matches, 0))
		{
		  int i;
		  for (i = 0; i < 10; i ++)
		  {
		    fprintf(stderr, "DEBUG: matches[%d].rm_so=%d\n", i,
		            (int)matches[i].rm_so);
		    if (matches[i].rm_so < 0)
		      break;

		    result ++;
		  }
		}

		regfree(&re);
	      }
	      break;
	  default :
	      result = 1;
	      break;
	}
      }

      fprintf(stderr,
              "DEBUG2: %*sStarting \"{%s%c%s\" at %ld, result=%d...\n",
	      indent, "", name, op, compare, ftell(in), result);

      if (result)
      {
       /*
	* Comparison true; output first part and ignore second...
	*/

        fprintf(stderr, "DEBUG2: %*sOutput first part...\n", indent, "");
	cgi_copy(out, in, element, ':', indent + 2);

        fprintf(stderr, "DEBUG2: %*sSkip second part...\n", indent, "");
	cgi_copy(NULL, in, element, '}', indent + 2);
      }
      else
      {
       /*
	* Comparison false; ignore first part and output second...
	*/

        fprintf(stderr, "DEBUG2: %*sSkip first part...\n", indent, "");
	cgi_copy(NULL, in, element, ':', indent + 2);

        fprintf(stderr, "DEBUG2: %*sOutput second part...\n", indent, "");
	cgi_copy(out, in, element, '}', indent + 2);
      }

      fprintf(stderr, "DEBUG2: %*sFinished \"{%s%c%s\", out=%p...\n", indent, "",
              name, op, compare, out);
    }
    else if (ch == '\\')	/* Quoted char */
    {
      if (out)
        putc(getc(in), out);
      else
        getc(in);
    }
    else if (out)
      putc(ch, out);

  if (ch == EOF)
    fprintf(stderr, "DEBUG2: %*sReturning at file position %ld on EOF...\n",
	    indent, "", ftell(in));
  else
    fprintf(stderr,
            "DEBUG2: %*sReturning at file position %ld on character '%c'...\n",
	    indent, "", ftell(in), ch);

  if (ch == EOF && term)
    fprintf(stderr, "ERROR: %*sSaw EOF, expected '%c'!\n", indent, "", term);

 /*
  * Flush any pending output...
  */

  if (out)
    fflush(out);
}