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); }
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(); }
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); }
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); }