/* This routine runs after all incoming data has been received */ static void runCgi(MaQueue *q) { MaResponse *resp; MaConn *conn; MprCmd *cmd; conn = q->conn; resp = conn->response; cmd = (MprCmd*) q->queueData; if (cmd == 0) { startCgi(q); cmd = (MprCmd*) q->queueData; if (q->pair->count > 0) { writeToCGI(q->pair); } } /* Close the CGI program's stdin. This will allow it to exit if it was expecting input data. */ mprCloseCmdFd(cmd, MPR_CMD_STDIN); if (conn->requestFailed) { maPutForService(q, maCreateEndPacket(q), 1); return; } while (mprWaitForCmd(cmd, 1000) < 0) { if (mprGetElapsedTime(cmd, cmd->lastActivity) >= conn->host->timeout) { break; } } if (cmd->pid == 0) { maPutForService(q, maCreateEndPacket(q), 1); } else { mprStopCmd(cmd); mprReapCmd(cmd, MPR_TIMEOUT_STOP_TASK); cmd->status = 255; } }
/* This routine runs a command and waits for its completion. Stdoutput and Stderr are returned in *out and *err respectively. The command returns the exit status of the command. Valid flags are: MPR_CMD_NEW_SESSION Create a new session on Unix MPR_CMD_SHOW Show the commands window on Windows MPR_CMD_IN Connect to stdin */ PUBLIC int mprRunCmdV(MprCmd *cmd, int argc, cchar **argv, cchar **envp, cchar *in, char **out, char **err, MprTicks timeout, int flags) { ssize len; int rc, status; assert(cmd); if (in) { flags |= MPR_CMD_IN; } if (err) { *err = 0; flags |= MPR_CMD_ERR; } else { flags &= ~MPR_CMD_ERR; } if (out) { *out = 0; flags |= MPR_CMD_OUT; } else { flags &= ~MPR_CMD_OUT; } if (flags & MPR_CMD_OUT) { cmd->stdoutBuf = mprCreateBuf(ME_BUFSIZE, -1); } if (flags & MPR_CMD_ERR) { cmd->stderrBuf = mprCreateBuf(ME_BUFSIZE, -1); } mprSetCmdCallback(cmd, defaultCmdCallback, NULL); rc = mprStartCmd(cmd, argc, argv, envp, flags); if (in) { len = slen(in); if (mprWriteCmdBlock(cmd, MPR_CMD_STDIN, in, len) != len) { *err = sfmt("Cannot write to command %s", cmd->program); return MPR_ERR_CANT_WRITE; } } if (cmd->files[MPR_CMD_STDIN].fd >= 0) { mprFinalizeCmd(cmd); } if (rc < 0) { if (err) { if (rc == MPR_ERR_CANT_ACCESS) { *err = sfmt("Cannot access command %s", cmd->program); } else if (rc == MPR_ERR_CANT_OPEN) { *err = sfmt("Cannot open standard I/O for command %s", cmd->program); } else if (rc == MPR_ERR_CANT_CREATE) { *err = sfmt("Cannot create process for %s", cmd->program); } } return rc; } if (cmd->flags & MPR_CMD_DETACH) { return 0; } if (mprWaitForCmd(cmd, timeout) < 0) { mprRemoveItem(MPR->cmdService->cmds, cmd); return MPR_ERR_NOT_READY; } if ((status = mprGetCmdExitStatus(cmd)) < 0) { mprRemoveItem(MPR->cmdService->cmds, cmd); return MPR_ERR; } if (err && flags & MPR_CMD_ERR) { *err = mprGetBufStart(cmd->stderrBuf); } if (out && flags & MPR_CMD_OUT) { *out = mprGetBufStart(cmd->stdoutBuf); } return status; }
PUBLIC int espEmail(HttpConn *conn, cchar *to, cchar *from, cchar *subject, MprTime date, cchar *mime, cchar *message, MprList *files) { MprList *lines; MprCmd *cmd; cchar *body, *boundary, *contents, *encoded, *file; char *out, *err; ssize length; int i, next, status; if (!from || !*from) { from = "anonymous"; } if (!subject || !*subject) { subject = "Mail message"; } if (!mime || !*mime) { mime = "text/plain"; } if (!date) { date = mprGetTime(); } boundary = sjoin("esp.mail=", mprGetMD5("BOUNDARY"), NULL); lines = mprCreateList(0, 0); mprAddItem(lines, sfmt("To: %s", to)); mprAddItem(lines, sfmt("From: %s", from)); mprAddItem(lines, sfmt("Date: %s", mprFormatLocalTime(0, date))); mprAddItem(lines, sfmt("Subject: %s", subject)); mprAddItem(lines, "MIME-Version: 1.0"); mprAddItem(lines, sfmt("Content-Type: multipart/mixed; boundary=%s", boundary)); mprAddItem(lines, ""); boundary = sjoin("--", boundary, NULL); mprAddItem(lines, boundary); mprAddItem(lines, sfmt("Content-Type: %s", mime)); mprAddItem(lines, ""); mprAddItem(lines, ""); mprAddItem(lines, message); for (ITERATE_ITEMS(files, file, next)) { mprAddItem(lines, boundary); if ((mime = mprLookupMime(NULL, file)) == 0) { mime = "application/octet-stream"; } mprAddItem(lines, "Content-Transfer-Encoding: base64"); mprAddItem(lines, sfmt("Content-Disposition: inline; filename=\"%s\"", mprGetPathBase(file))); mprAddItem(lines, sfmt("Content-Type: %s; name=\"%s\"", mime, mprGetPathBase(file))); mprAddItem(lines, ""); contents = mprReadPathContents(file, &length); encoded = mprEncode64Block(contents, length); for (i = 0; i < length; i += 76) { mprAddItem(lines, snclone(&encoded[i], i + 76)); } } mprAddItem(lines, sfmt("%s--", boundary)); body = mprListToString(lines, "\n"); httpTraceContent(conn, "esp.email", "context", body, slen(body), 0); cmd = mprCreateCmd(conn->dispatcher); if (mprRunCmd(cmd, "sendmail -t", NULL, body, &out, &err, -1, 0) < 0) { mprDestroyCmd(cmd); return MPR_ERR_CANT_OPEN; } if (mprWaitForCmd(cmd, ME_ESP_EMAIL_TIMEOUT) < 0) { httpTrace(conn, "esp.email.error", "error", "msg=\"Timeout waiting for command to complete\", timeout=%d, command=\"%s\"", ME_ESP_EMAIL_TIMEOUT, cmd->argv[0]); mprDestroyCmd(cmd); return MPR_ERR_CANT_COMPLETE; } if ((status = mprGetCmdExitStatus(cmd)) != 0) { httpTrace(conn, "esp.email.error", "error", "msg=\"Sendmail failed\", status=%d, error=\"%s\"", status, err); mprDestroyCmd(cmd); return MPR_ERR_CANT_WRITE; } mprDestroyCmd(cmd); return 0; }
/* * This routine runs a command and waits for its completion. Stdoutput and Stderr are returned in *out and *err * respectively. The command returns the exit status of the command. * Valid flags are: * MPR_CMD_NEW_SESSION Create a new session on Unix * MPR_CMD_SHOW Show the commands window on Windows * MPR_CMD_IN Connect to stdin */ int mprRunCmdV(MprCmd *cmd, int argc, char **argv, char **out, char **err, int flags) { int rc, status; if (err) { *err = 0; flags |= MPR_CMD_ERR; } else { flags &= ~MPR_CMD_ERR; } if (out) { *out = 0; flags |= MPR_CMD_OUT; } else { flags &= ~MPR_CMD_OUT; } if (flags & MPR_CMD_OUT) { mprFree(cmd->stdoutBuf); cmd->stdoutBuf = mprCreateBuf(cmd, MPR_BUFSIZE, -1); } if (flags & MPR_CMD_ERR) { mprFree(cmd->stderrBuf); cmd->stderrBuf = mprCreateBuf(cmd, MPR_BUFSIZE, -1); } mprSetCmdCallback(cmd, cmdCallback, NULL); lock(cmd); rc = mprStartCmd(cmd, argc, argv, NULL, flags); /* * Close the pipe connected to the client's stdin */ if (cmd->files[MPR_CMD_STDIN].fd >= 0) { mprCloseCmdFd(cmd, MPR_CMD_STDIN); } if (rc < 0) { if (err) { if (rc == MPR_ERR_CANT_ACCESS) { *err = mprAsprintf(cmd, -1, "Can't access command %s", cmd->program); } else if (MPR_ERR_CANT_OPEN) { *err = mprAsprintf(cmd, -1, "Can't open standard I/O for command %s", cmd->program); } else if (rc == MPR_ERR_CANT_CREATE) { *err = mprAsprintf(cmd, -1, "Can't create process for %s", cmd->program); } } unlock(cmd); return rc; } if (cmd->flags & MPR_CMD_DETACH) { unlock(cmd); return 0; } unlock(cmd); if (mprWaitForCmd(cmd, -1) < 0) { return MPR_ERR_NOT_READY; } lock(cmd); if (mprGetCmdExitStatus(cmd, &status) < 0) { unlock(cmd); return MPR_ERR; } if (err && flags & MPR_CMD_ERR) { mprAddNullToBuf(cmd->stderrBuf); *err = mprGetBufStart(cmd->stderrBuf); } if (out && flags & MPR_CMD_OUT) { mprAddNullToBuf(cmd->stdoutBuf); *out = mprGetBufStart(cmd->stdoutBuf); } unlock(cmd); return status; }