?? jobs.c++
字號:
/* $Id: Jobs.c++,v 1.29 2006/06/12 18:28:55 aidan Exp $ *//* * Copyright (c) 1995-1996 Sam Leffler * Copyright (c) 1995-1996 Silicon Graphics, Inc. * HylaFAX is a trademark of Silicon Graphics * * Permission to use, copy, modify, distribute, and sell this software and * its documentation for any purpose is hereby granted without fee, provided * that (i) the above copyright notices and this permission notice appear in * all copies of the software and related documentation, and (ii) the names of * Sam Leffler and Silicon Graphics may not be used in any advertising or * publicity relating to the software without the specific, prior written * permission of Sam Leffler and Silicon Graphics. * * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. * * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE * OF THIS SOFTWARE. */#include "port.h"#include "config.h"#include "Sys.h"#include "HylaFAXServer.h"#include "Dispatcher.h"#include "class2.h"#include <sys/file.h>#include <ctype.h>/* * Job state query and control commands. */Job::Job(const fxStr& qf, int f) : FaxRequest(qf,f){ lastmod = 0; queued = false;}Job::~Job() {}/* * We need to override the default logic because faxq * assumes it's working directory is at the top of the * spooling area and we may be elsewhere. We can also * simplify things because we know we're chroot'd to * the top of the spooling area--thus we don't need to * check for ``..'' and ``/'' being used to reference * files outside the spooling area. */boolJob::checkDocument(const char* pathname){ struct stat sb; if (FileCache::lookup(fxStr::format("/%s", pathname), sb)) return (true); int fd = Sys::open(pathname, 0); if (fd == -1) { logError("Can not access document file \"%s\": %s", pathname, strerror(errno)); return (false); } Sys::close(fd); logError("Undetermined error with document file \"%s\"", pathname); return (false);}fxIMPLEMENT_StrKeyPtrValueDictionary(JobDict, Job*)/* * Job state parameter access controls. * * There are three levels of access control applied to job state * information: administrator, owner, and other. * Access is controlled on a read+write basis. Write accesses * can be further restricted to constrain written values to * be within a range; this is used to allow users to change * parameters within a restricted range (e.g. to up the maximum * number of tries but still constrain it to a sane value). */#define A_RUSR 0400 // read permission: owner#define A_WUSR 0200 // abitrary write permission: owner#define A_MUSR 0100 // restricted write permission: owner#define A_RADM 0040 // read permission: administrator#define A_WADM 0020 // abitrary write permission: administrator#define A_MADM 0010 // restricted write permission: administrator#define A_ROTH 0004 // read permission: other#define A_WOTH 0002 // abitrary write permission: other#define A_MOTH 0001 // restricted write permission: other#define A_READ 004#define A_WRITE 002#define A_MODIFY 001#define N(a) (sizeof (a) / sizeof (a[0]))static const struct { Token t; u_int protect; // read+write protection} params[] = { { T_BEGBR, A_RUSR|A_WUSR|A_RADM|A_WADM|A_ROTH }, { T_BEGST, A_RUSR|A_WUSR|A_RADM|A_WADM|A_ROTH }, { T_CHOPTHRESH, A_RUSR|A_WUSR|A_RADM|A_WADM|A_ROTH }, { T_CLIENT, A_RUSR|A_RADM|A_WADM|A_ROTH }, { T_COMMID, A_RUSR|A_RADM|A_ROTH }, { T_COMMENTS, A_RUSR|A_WUSR|A_RADM|A_WADM|A_ROTH }, { T_COVER, A_RUSR|A_WUSR|A_RADM|A_WADM|A_ROTH }, { T_DATAFORMAT, A_RUSR|A_WUSR|A_RADM|A_WADM|A_ROTH }, { T_DIALSTRING, A_RUSR|A_WUSR|A_RADM|A_WADM }, { T_DOCUMENT, A_RUSR|A_WUSR|A_RADM|A_WADM|A_ROTH }, { T_DONEOP, A_RUSR|A_WUSR|A_RADM|A_WADM|A_ROTH }, { T_EXTERNAL, A_RUSR|A_WUSR|A_RADM|A_WADM|A_ROTH }, { T_FAXNUMBER, A_RUSR|A_WUSR|A_RADM|A_WADM|A_ROTH }, { T_FROM_COMPANY, A_RUSR|A_WUSR|A_RADM|A_WADM|A_ROTH }, { T_FROM_LOCATION, A_RUSR|A_WUSR|A_RADM|A_WADM|A_ROTH }, { T_FROM_USER, A_RUSR|A_WUSR|A_RADM|A_WADM|A_ROTH }, { T_FROM_VOICE, A_RUSR|A_WUSR|A_RADM|A_WADM|A_ROTH }, { T_GROUPID, A_RUSR|A_RADM|A_ROTH }, { T_JOBID, A_RUSR|A_RADM|A_ROTH }, { T_JOBINFO, A_RUSR|A_WUSR|A_RADM|A_WADM|A_ROTH }, { T_JOBTYPE, A_RUSR|A_RADM|A_ROTH }, { T_LASTTIME, A_RUSR|A_MUSR|A_RADM|A_WADM|A_ROTH }, { T_MAXDIALS, A_RUSR|A_MUSR|A_RADM|A_WADM|A_ROTH }, { T_MAXPAGES, A_RUSR|A_MUSR|A_RADM|A_WADM|A_ROTH }, { T_MAXTRIES, A_RUSR|A_MUSR|A_RADM|A_WADM|A_ROTH }, { T_MINBR, A_RUSR|A_WUSR|A_RADM|A_WADM|A_ROTH }, { T_MODEM, A_RUSR|A_WUSR|A_RADM|A_WADM|A_ROTH }, { T_OWNER, A_RUSR|A_RADM|A_WADM|A_ROTH }, { T_NDIALS, A_RUSR|A_RADM|A_ROTH }, { T_NOTIFY, A_RUSR|A_WUSR|A_RADM|A_WADM|A_ROTH }, { T_NOTIFYADDR, A_RUSR|A_WUSR|A_RADM|A_WADM|A_ROTH }, { T_NPAGES, A_RUSR|A_RADM|A_ROTH }, { T_NTRIES, A_RUSR|A_RADM|A_ROTH }, { T_PAGECHOP, A_RUSR|A_WUSR|A_RADM|A_WADM|A_ROTH }, { T_PAGELENGTH, A_RUSR|A_WUSR|A_RADM|A_WADM|A_ROTH }, { T_PAGEWIDTH, A_RUSR|A_WUSR|A_RADM|A_WADM|A_ROTH }, { T_PASSWD, A_RUSR|A_WUSR|A_RADM|A_WADM }, { T_POLL, A_RUSR|A_WUSR|A_RADM|A_WADM|A_ROTH }, { T_REGARDING, A_RUSR|A_MUSR|A_RADM|A_WADM|A_ROTH }, { T_RETRYTIME, A_RUSR|A_MUSR|A_RADM|A_WADM|A_ROTH }, { T_SCHEDPRI, A_RUSR|A_MUSR|A_RADM|A_WADM|A_ROTH }, { T_SENDTIME, A_RUSR|A_WUSR|A_RADM|A_WADM|A_ROTH }, { T_STATE, A_RUSR|A_RADM|A_ROTH }, { T_STATUS, A_RUSR|A_RADM|A_WADM|A_ROTH }, { T_SUBADDR, A_RUSR|A_WUSR|A_RADM|A_WADM|A_ROTH }, { T_TAGLINE, A_RUSR|A_WUSR|A_RADM|A_WADM|A_ROTH }, { T_TOTDIALS, A_RUSR|A_RADM|A_ROTH }, { T_TOTPAGES, A_RUSR|A_RADM|A_ROTH }, { T_TOTTRIES, A_RUSR|A_RADM|A_ROTH }, { T_TO_COMPANY, A_RUSR|A_WUSR|A_RADM|A_WADM|A_ROTH }, { T_TO_LOCATION, A_RUSR|A_WUSR|A_RADM|A_WADM|A_ROTH }, { T_TO_USER, A_RUSR|A_WUSR|A_RADM|A_WADM|A_ROTH }, { T_TO_VOICE, A_RUSR|A_WUSR|A_RADM|A_WADM|A_ROTH }, { T_TSI, A_RUSR|A_WUSR|A_RADM|A_WADM|A_ROTH }, { T_USE_CONTCOVER, A_RUSR|A_RADM|A_WADM|A_ROTH }, { T_USE_ECM, A_RUSR|A_WUSR|A_RADM|A_WADM|A_ROTH }, { T_USE_TAGLINE, A_RUSR|A_WUSR|A_RADM|A_WADM|A_ROTH }, { T_USE_XVRES, A_RUSR|A_WUSR|A_RADM|A_WADM|A_ROTH }, { T_USRKEY, A_RUSR|A_WUSR|A_RADM|A_WADM|A_ROTH }, { T_VRES, A_RUSR|A_WUSR|A_RADM|A_WADM|A_ROTH }, { T_NIL, 0 },};/* * Check client permission to do the specified operation * on the specified job state parameter. Operation can * be a combination of A_READ+A_WRITE+A_MODIFY. Note that * ownership is based on login account and not fax uid; * this may need to be rethought. */boolHylaFAXServer::checkAccess(const Job& job, Token t, u_int op){ u_int m = 0; if (t == T_JOB) { m = jobProtection; } else { u_int n = N(params)-1; u_int i = 0; while (i < n && params[i].t != t) i++; m = params[i].protect; } if (m&op) // other/public access return (true); if (IS(PRIVILEGED) && ((m>>3)&op)) // administrative access return (true); if (job.owner == the_user && ((m>>6)&op)) // owner access return (true);#if 0 if (checkOwnerUid && ((m>>6)&op)) // owner UID access return (true);#endif return (false);}static struct { Token t; fxStr Job::* p;} strvals[] = { { T_JOBTYPE, &Job::jobtype }, { T_EXTERNAL, &Job::external }, { T_DIALSTRING, &Job::number }, { T_NOTIFYADDR, &Job::mailaddr }, { T_USRKEY, &Job::jobtag }, { T_MODEM, &Job::modem }, { T_TO_USER, &Job::receiver }, { T_TO_COMPANY, &Job::company }, { T_TO_LOCATION, &Job::location }, { T_TO_VOICE, &Job::voice }, { T_FROM_USER, &Job::sender }, { T_FROM_COMPANY, &Job::fromcompany }, { T_FROM_LOCATION, &Job::fromlocation }, { T_FROM_VOICE, &Job::fromvoice }, { T_PASSWD, &Job::passwd }, { T_CLIENT, &Job::client }, { T_FAXNUMBER, &Job::faxnumber }, { T_TSI, &Job::tsi }, { T_TAGLINE, &Job::tagline }, { T_SUBADDR, &Job::subaddr }, { T_GROUPID, &Job::groupid }, { T_JOBID, &Job::jobid }, { T_JOBINFO, &Job::jobtag }, { T_OWNER, &Job::owner }, { T_STATUS, &Job::notice }, { T_DONEOP, &Job::doneop }, { T_COMMID, &Job::commid }, { T_REGARDING, &Job::regarding }, { T_COMMENTS, &Job::comments },};static struct { Token t; u_short Job::* p;} shortvals[] = { { T_TOTPAGES, &Job::totpages }, { T_NPAGES, &Job::npages }, { T_NTRIES, &Job::ntries }, { T_NDIALS, &Job::ndials }, { T_TOTDIALS, &Job::totdials }, { T_MAXDIALS, &Job::maxdials }, { T_TOTTRIES, &Job::tottries }, { T_MAXTRIES, &Job::maxtries }, { T_PAGEWIDTH, &Job::pagewidth }, { T_PAGELENGTH, &Job::pagelength }, { T_VRES, &Job::resolution }, { T_SCHEDPRI, &Job::usrpri }, { T_MINBR, &Job::minbr }, { T_BEGBR, &Job::desiredbr }, { T_BEGST, &Job::desiredst },};static const char* notifyVals[4] = { "NONE", // no_notice "DONE", // when_done "REQUEUE", // when_requeued "DONE+REQUEUE" // when_done|when_requeued};static const char* chopVals[4] = { "DEFAULT", // chop_default "NONE", // chop_none "ALL", // chop_all "LAST" // chop_last};static const char* dataVals[] = { "G31D", // Group 3, 1-D "G32D", // Group 3, 2-D "G32DUNC", // Group 3, 2-D (w/ uncompressed) "G4" // Group 4};static const char* stateVals[] = { "UNDEFINED", // undefined state (should never be used) "SUSPENDED", // not being scheduled "PENDING", // waiting for time to send "SLEEPING", // waiting for scheduled timeout "BLOCKED", // blocked by concurrent activity "READY", // ready to be go, waiting for resources "ACTIVE", // actively being processed "DONE", // processing completed with success "FAILED", // processing completed with failure};static const char* docTypeNames[] = { "FAX", // send_fax "TIFF", // send_tiff "TIFF", // send_tiff_saved "PDF", // send_pdf "PDF", // send_pdf_saved "PS", // send_postscript "PS", // send_postscript_saved "PCL", // send_pcl "PCL", // send_pcl_saved "DATA", // send_data "DATA", // send_data_saved "POLL", // send_poll "PAGE", // send_page "PAGE", // send_page_saved "UUCP", // send_uucp "UNKNOWN", // send_unknown};static const char*boolString(bool b){ return (b ? "YES" : "NO");}voidHylaFAXServer::replyBoolean(int code, bool b){ reply(code, "%s", boolString(b));}/* * Check that the job's in-memory state is consistent * with what is on disk. If the on-disk state is newer then * read it in. If the job has been removed then remove our * reference, reset the current job back to the default job, * and send the client an error reply. This method is used * before each place a job's state is access. */boolHylaFAXServer::checkJobState(Job* job){ /* * Verify job is still around (another process has * not deleted it) and if the on-disk state has * been updated, re-read the job description file. */ struct stat sb; if (!FileCache::update("/" | job->qfile, sb)) { jobs.remove(job->jobid); if (job == curJob) // make default job current curJob = &defJob; delete job, job = NULL; return (false); } if (job->lastmod < sb.st_mtime) { (void) updateJobFromDisk(*job); job->lastmod = sb.st_mtime; } return (true);}/* * Check if it's ok to do the specified operation on the * current job's state parameter. If not, return the appropriate * error reply. We disallow modifications on jobs that * do not appear to be suspended since otherwise the mods * could be lost (in our case they will be lost due to the * way that things work). */boolHylaFAXServer::checkParm(Job& job, Token t, u_int op){ if (!checkJobState(&job)) { // insure consistent state reply(500, "Cannot access job state; job deleted by another party."); return (false); } else if (!checkAccess(job, t, op)) { reply(503, "Permission denied: no %s access to job parameter %s." , (op == A_READ ? "read" : "write") , parmToken(t) ); return (false); } else if ((op & (A_WRITE|A_MODIFY)) && job.state != FaxRequest::state_suspended && job.jobid != "default") { reply(503, "Suspend the job with JSUSP first."); return (false); } else return (true);}/* * Respond to a job state parameter query. */voidHylaFAXServer::replyJobParamValue(Job& job, int code, Token t){ if (!checkParm(job, t, A_READ)) return; u_int i, n; switch (t) { case T_SENDTIME: if (job.tts != 0) { const struct tm* tm = cvtTime(job.tts); // XXX should this include seconds? reply(code, "%4d%02d%02d%02d%02d%02d" , tm->tm_year+1900 , tm->tm_mon+1 , tm->tm_mday , tm->tm_hour , tm->tm_min , tm->tm_sec ); } else reply(code, "NOW"); return; case T_LASTTIME: time_t tv; tv = job.killtime - job.tts; // XXX for __GNUC__ reply(code, "%02d%02d%02d", tv/(24*60*60), (tv/(60*60))%24, (tv/60)%60); return; case T_RETRYTIME: reply(code, "%02d%02d", job.retrytime/60, job.retrytime%60); return; case T_STATE: reply(code, "%s", stateVals[job.state]); return; case T_NOTIFY: reply(code, "%s", notifyVals[job.notify]); return; case T_PAGECHOP: reply(code, "%s", chopVals[job.pagechop]); return; case T_CHOPTHRESH: reply(code, "%g", job.chopthreshold); return; case T_DATAFORMAT: reply(code, "%s", dataVals[job.desireddf]); return; case T_USE_ECM: replyBoolean(code, job.desiredec); return; case T_USE_TAGLINE: replyBoolean(code, job.desiredtl); return; case T_USE_XVRES: replyBoolean(code, job.usexvres); return; case T_USE_CONTCOVER: replyBoolean(code, job.useccover); return; case T_DOCUMENT: for (i = 0, n = job.items.length(); i < n; i++) { const FaxItem& fitem = job.items[i]; // XXX should cover page docs not be shown? switch (fitem.op) { case FaxRequest::send_pdf: case FaxRequest::send_pdf_saved: case FaxRequest::send_tiff: case FaxRequest::send_tiff_saved: case FaxRequest::send_postscript: case FaxRequest::send_postscript_saved: case FaxRequest::send_pcl: case FaxRequest::send_pcl_saved: lreply(code, "%s %s", docTypeNames[fitem.op], (const char*) fitem.item); break; } } reply(code, "End of documents."); return; case T_COVER: for (i = 0, n = job.items.length(); i < n; i++) { const FaxItem& fitem = job.items[i]; if (fitem.item.length() > 7 && fitem.item.tail(6) == ".cover") { switch (fitem.op) { case FaxRequest::send_tiff: case FaxRequest::send_tiff_saved: case FaxRequest::send_pdf: case FaxRequest::send_pdf_saved: case FaxRequest::send_postscript: case FaxRequest::send_postscript_saved: case FaxRequest::send_pcl: case FaxRequest::send_pcl_saved: reply(code, "%s %s", docTypeNames[fitem.op], (const char*) fitem.item); return; } } } reply(code+1, "No cover page document."); return; case T_POLL: for (i = 0, n = job.items.length(); i < n; i++) { const FaxItem& fitem = job.items[i]; if (fitem.op == FaxRequest::send_poll) lreply(code, "\"%s\" \"%s\"", (const char*) fitem.item, (const char*) fitem.addr); } reply(code, "End of polling items."); return; } for (i = 0, n = N(strvals); i < n; i++) if (strvals[i].t == t) { reply(code, "%s", (const char*) (job.*strvals[i].p)); return; } for (i = 0, n = N(shortvals); i < n; i++) if (shortvals[i].t == t) { reply(code, "%u", job.*shortvals[i].p); return; } reply(500, "Botch: no support for querying parameter value.");}void
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -