Trigger.c++
上传用户:weiyuanprp
上传日期:2020-05-20
资源大小:1169k
文件大小:12k
源码类别:

传真(Fax)编程

开发平台:

C/C++

  1. /* $Id: Trigger.c++,v 1.2 2008/04/28 23:59:00 faxguy Exp $ */
  2. /*
  3.  * Copyright (c) 1990-1996 Sam Leffler
  4.  * Copyright (c) 1991-1996 Silicon Graphics, Inc.
  5.  * HylaFAX is a trademark of Silicon Graphics
  6.  *
  7.  * Permission to use, copy, modify, distribute, and sell this software and 
  8.  * its documentation for any purpose is hereby granted without fee, provided
  9.  * that (i) the above copyright notices and this permission notice appear in
  10.  * all copies of the software and related documentation, and (ii) the names of
  11.  * Sam Leffler and Silicon Graphics may not be used in any advertising or
  12.  * publicity relating to the software without the specific, prior written
  13.  * permission of Sam Leffler and Silicon Graphics.
  14.  * 
  15.  * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, 
  16.  * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY 
  17.  * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.  
  18.  * 
  19.  * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
  20.  * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
  21.  * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
  22.  * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF 
  23.  * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE 
  24.  * OF THIS SOFTWARE.
  25.  */
  26. #include "port.h"
  27. #include "Sys.h"
  28. #include "config.h"
  29. #include "HylaFAXServer.h"
  30. #include "Dispatcher.h"
  31. #include "ModemExt.h"
  32. #include "JobExt.h"
  33. #include "FaxRecvInfo.h"
  34. #include "FaxSendInfo.h"
  35. /*
  36.  * Setup a trigger to monitor server events and
  37.  * return ascii/binary event information on a
  38.  * data connection.
  39.  */
  40. void
  41. HylaFAXServer::triggerCmd(const char* fmt ...)
  42. {
  43.     /*
  44.      * We setup the connection before registering the
  45.      * trigger to reduce lost event reports.  If we setup
  46.      * the trigger first then events could come in and
  47.      * be discarded while we were setting up the data
  48.      * connection.  Either way we may still lose some
  49.      * events if, for example, the client wants to
  50.      * fully monitor a submitted job using a single
  51.      * control channel.  The only way to reliably do
  52.      * this is to register a trigger before a job is
  53.      * submitted (sigh).
  54.      */
  55.     int code;
  56.     FILE* dout = openDataConn("w", code);
  57.     if (dout != NULL) {
  58. va_list ap;
  59. va_start(ap, fmt);
  60. trigSpec = fxStr::vformat(fmt, ap);
  61. va_end(ap);
  62. reply(code, "%s for trigger "%s".", dataConnMsg(code),
  63.     (const char*) trigSpec);
  64. state |= S_LOGTRIG; // force events to be reported
  65. fxStr emsg;
  66. if (loadTrigger(emsg)) {
  67.     if (setjmp(urgcatch) == 0) {
  68. state |= S_TRANSFER;
  69. /*
  70.  * The only way out of this is a client
  71.  * ABORt request or if the control channel
  72.  * connection is broken.
  73.  */
  74. for (;;)
  75.     Dispatcher::instance().dispatch();
  76.     } else
  77. perror_reply(426, "Data connection", errno);
  78.     state &= ~S_TRANSFER;
  79.     (void) cancelTrigger(emsg);
  80. } else
  81.     reply(504, "Cannot register trigger: %s.", (const char*) emsg);
  82. state &= ~S_LOGTRIG;
  83. closeDataConn(dout);
  84.     }
  85. }
  86. /*
  87.  * Create a trigger for the specified events
  88.  * and return the identifier sent back by the
  89.  * scheduler.
  90.  */
  91. bool
  92. HylaFAXServer::newTrigger(fxStr& emsg, const char* fmt, ...)
  93. {
  94.     va_list ap;
  95.     va_start(ap, fmt);
  96.     bool b = vnewTrigger(emsg, fmt, ap);
  97.     va_end(ap);
  98.     return (b);
  99. }
  100. bool
  101. HylaFAXServer::vnewTrigger(fxStr& emsg, const char* fmt, va_list ap)
  102. {
  103.     trigSpec = fxStr::vformat(fmt, ap);
  104.     return (loadTrigger(emsg));
  105. }
  106. /*
  107.  * Send the current trigger specification to the scheduler
  108.  * and stash the returned trigger ID.  This is used to
  109.  * create triggers the first time as well as to re-load an
  110.  * active trigger if the scheduler is restarted.
  111.  */
  112. bool
  113. HylaFAXServer::loadTrigger(fxStr& emsg)
  114. {
  115.     if (sendQueuerACK(emsg, "T%s", (const char*) trigSpec) &&
  116.       fifoResponse.length() > 2) {
  117. tid = atoi(&fifoResponse[2]);
  118. return (true);
  119.     } else
  120. return (false);
  121. }
  122. /*
  123.  * Inform the spooler that it should cancel
  124.  * a previously created trigger.
  125.  */
  126. bool
  127. HylaFAXServer::cancelTrigger(fxStr& emsg)
  128. {
  129.     trigSpec = ""; // avoid spontaneous reloads
  130.     return sendQueuer(emsg, "D%u", tid);
  131. }
  132. /*
  133.  * Handle a trigger event received while waiting
  134.  * for a job or group of jobs.  The status information
  135.  * is sent back to the client over the data channel
  136.  * if S_LOGTRIG is set in the server state.
  137.  */
  138. void
  139. HylaFAXServer::triggerEvent(const TriggerMsgHeader& h, const char* cp)
  140. {
  141. #define EventType(e) ((e)>>4)
  142.     int evt = EventType(h.event);
  143.     if (evt == EventType(JOB_BASE) || evt == EventType(SEND_BASE)) {
  144. JobExt job;
  145. cp = job.decode(cp);
  146. /*
  147.  * Propagate job state for clients that are doing
  148.  * things like waiting for a job to complete.  This
  149.  * may be fairly costly if someone traces all jobs
  150.  * as it'll cause the in-memory job database to grow.
  151.  */
  152. fxStr emsg;
  153. Job* jp = findJob(job.jobid, emsg);
  154. if (jp) {
  155.     jp->tts = job.tts;
  156.     jp->killtime = job.killtime;
  157.     jp->state = job.state;
  158.     jp->pri = job.pri;
  159.     jp->commid = job.commid;
  160. }
  161. if (IS(LOGTRIG) && type == TYPE_A) {
  162.     if (evt == EventType(JOB_BASE))
  163. logJobEventMsg(h, job);
  164.     else
  165. logSendEventMsg(h, job, cp);
  166. }
  167.     } else if (evt == EventType(MODEM_BASE) || evt == EventType(RECV_BASE)) {
  168. ModemExt modem;
  169. cp = modem.decode(cp);
  170. if (evt == EventType(RECV_BASE))
  171. {
  172.     FaxRecvInfo ri;
  173.     ri.decode(cp);
  174.     /*
  175.      * Update/record receive queue status.
  176.      */
  177.     RecvInfo* rip = recvq[ri.qfile];
  178.     if (!rip)
  179. recvq[ri.qfile] = rip = new RecvInfo(ri.qfile);
  180.     if (rip->recvTime == 0)
  181. rip->recvTime = h.tstamp;
  182.     if (h.event == Trigger::RECV_END) {
  183. rip->beingReceived = false;
  184. rip->reason = ri.reason;
  185.     } else
  186. rip->beingReceived = true;
  187.     rip->sender = ri.sender;
  188.     rip->subaddr = ri.subaddr;
  189.     rip->npages = ri.npages;
  190.     rip->time = h.tstamp - rip->recvTime;
  191.     rip->commid = ri.commid;
  192.     if (IS(LOGTRIG) && type == TYPE_A)
  193. logRecvEventMsg(h, ri, cp);
  194. } else if (IS(LOGTRIG) && type == TYPE_A)
  195.     logModemEventMsg(h, modem, cp);
  196.     } else {
  197. logError("Unrecognized trigger event message %u.", h.event);
  198. return;
  199.     }
  200.     if (IS(LOGTRIG) && type == TYPE_I) {
  201. /*
  202.  * Binary trigger logging causes the raw event
  203.  * stream to pass through to the user.  This is
  204.  * probably not a great idea as it causes clients
  205.  * to be aware of the server's internal message
  206.  * formats but for some applications it may be
  207.  * appropriate.  We support it now to better
  208.  * understand the implications.
  209.  */
  210. (void) Sys::write(data, cp - sizeof (h), h.length);
  211.     }
  212. #undef EventType
  213. }
  214. /*
  215.  * Ascii Trigger Event Logging Support.
  216.  */
  217. #define unknownEvent "Unknown event" // XXX for HP CC
  218. void
  219. HylaFAXServer::logEventMsg(const TriggerMsgHeader& h, fxStr& msg)
  220. {
  221.     struct tm& tm = *cvtTime(h.tstamp);
  222.     msg.insert(fxStr::format("%02d%02d%02d %d "
  223. , tm.tm_hour
  224. , tm.tm_min
  225. , tm.tm_sec
  226. , 100+h.event
  227.     ));
  228.     msg.append("rn");
  229.     (void) Sys::write(data, msg, msg.length());
  230. }
  231. /*
  232.  * Format and log a job event.
  233.  */
  234. void
  235. HylaFAXServer::logJobEventMsg(const TriggerMsgHeader& h, const JobExt& job)
  236. {
  237.     static const char* jobNames[16] = {
  238. "Created",
  239. "Suspended",
  240. "Ready to send",
  241. "Sleeping awaiting time-to-send",
  242. "Marked dead",
  243. "Being processed by scheduler",
  244. "Corpus reaped",
  245. "Activated",
  246. "Rejected",
  247. "Killed",
  248. "Blocked by another job",
  249. "Delayed by time-of-day restriction or similar",
  250. "Parameters altered",
  251. "Timed out",
  252. "Preparation started",
  253. "Preparation finished",
  254.     };
  255.     fxStr msg = fxStr::format("JOB %s (dest %s pri %u com %s): %s"
  256. , (const char*) job.jobid
  257. , (const char*) job.dest
  258. , job.pri
  259. , (const char*) job.commid
  260. , jobNames[h.event&0xf]
  261.     );
  262.     logEventMsg(h, msg);
  263. }
  264. static void
  265. addParams(fxStr& msg, const Class2Params& params)
  266. {
  267.     msg.append(fxStr::format("<%s, %s, %s, %s, %s>"
  268. , (params.ln == LN_A4 ? "A4" : params.ln == LN_B4 ? "B4" : "INF")
  269. , params.verticalResName()
  270. , params.dataFormatName()
  271. , params.bitRateName()
  272. , params.scanlineTimeName()
  273.     ));
  274. }
  275. /*
  276.  * Format and log a send event.
  277.  */
  278. void
  279. HylaFAXServer::logSendEventMsg(const TriggerMsgHeader& h, const JobExt& job, const char* cp)
  280. {
  281.     fxStr msg = fxStr::format("JOB %s (dest %s pri %u com %s): SEND FAX: "
  282. , (const char*) job.jobid
  283. , (const char*) job.dest
  284. , job.pri
  285. , (const char*) job.commid
  286.     );
  287.     if (h.event != Trigger::SEND_POLLRCVD) {
  288. static const char* sendNames[16] = {
  289.     "Begin attempt", // SEND_BEGIN
  290.     "Call placed (off-hook)", // SEND_CALL
  291.     "Connected to remote device", // SEND_CONNECTED
  292.     unknownEvent, // SEND_PAGE
  293.     unknownEvent, // SEND_DOC
  294.     unknownEvent, // SEND_POLLRCVD
  295.     unknownEvent, // SEND_POLLDONE
  296.     "Finished attempt", // SEND_END
  297.     "Reformat documents because of capabilities mismatch",
  298.     "Requeue job", // SEND_REQUEUE
  299.     "Job completed successfully", // SEND_DONE
  300.     unknownEvent,
  301.     unknownEvent,
  302.     unknownEvent,
  303.     unknownEvent,
  304.     unknownEvent
  305. };
  306. FaxSendInfo si;
  307. switch (h.event) {
  308. case Trigger::SEND_PAGE: // page sent
  309.     si.decode(cp);
  310.     msg.append(fxStr::format("Page %u sent in %s (file %s) "
  311. , si.npages
  312. , fmtTime(si.time)
  313. , (const char*) si.qfile
  314.     ));
  315.     addParams(msg, si.params);
  316.     break;
  317. case Trigger::SEND_DOC: // document sent
  318.     si.decode(cp);
  319.     msg.append(fxStr::format("Document sent in %s (file %s)"
  320. , fmtTime(si.time)
  321. , (const char*) si.qfile
  322.     ));
  323.     break;
  324. case Trigger::SEND_POLLDONE: // polling operation done
  325.     si.decode(cp);
  326.     msg.append(fxStr::format("Poll completed in %s (file %s)"
  327. , fmtTime(si.time)
  328. , (const char*) si.qfile
  329.     ));
  330.     break;
  331. default:
  332.     msg.append(sendNames[h.event&15]);
  333.     break;
  334. }
  335.     } else {
  336. FaxRecvInfo ri;
  337. ri.decode(cp);
  338. msg.append(fxStr::format("Recv polled document from %s, %u pages in %s, file %s"
  339.     , (const char*) ri.sender
  340.     , ri.npages
  341.     , fmtTime((time_t) ri.time)
  342.     , (const char*) ri.qfile
  343. ));
  344.     }
  345.     logEventMsg(h, msg);
  346. }
  347. /*
  348.  * Format and log a modem event.
  349.  */
  350. void
  351. HylaFAXServer::logModemEventMsg(const TriggerMsgHeader& h, const ModemExt& modem, const char* cp)
  352. {
  353.     static const char* modemNames[16] = {
  354. "Assigned to job",
  355. "Released by job",
  356. "Marked down",
  357. "Marked ready",
  358. "Marked busy",
  359. "Considered wedged",
  360. "In-use by an outbound job",
  361. "Inbound data call begin",
  362. "Inbound data call completed",
  363. "Inbound voice call begin",
  364. "Inbound voice call completed",
  365. "Caller-id information: ",
  366. unknownEvent,
  367. unknownEvent,
  368. unknownEvent,
  369. unknownEvent
  370.     };
  371.     fxStr msg = fxStr::format("MODEM %s: %s"
  372. , (const char*) modem.devID
  373. , modemNames[h.event&15]
  374.     );
  375.     if (h.event == Trigger::MODEM_CID)
  376. msg.append(cp);
  377.     logEventMsg(h, msg);
  378. }
  379. /*
  380.  * Format and log a facsimile receive event.
  381.  */
  382. void
  383. HylaFAXServer::logRecvEventMsg(const TriggerMsgHeader& h, const FaxRecvInfo& ri, const char*)
  384. {
  385.     fxStr msg = fxStr::format("RECV FAX: ");
  386.     switch (h.event) {
  387.     case Trigger::RECV_BEGIN:
  388. msg.append("Call started");
  389. break;
  390.     case Trigger::RECV_END:
  391. msg.append("Call ended");
  392. break;
  393.     case Trigger::RECV_START:
  394. msg.append(fxStr::format("Session started (com %s), TSI "%s" "
  395.     , (const char*) ri.commid
  396.     , (const char*) ri.sender
  397. ));
  398. addParams(msg, ri.params);
  399. break;
  400.     case Trigger::RECV_PAGE:
  401. msg.append(fxStr::format("From %s (com %s), page %u in %s "
  402.     , (const char*) ri.sender
  403.     , (const char*) ri.commid
  404.     , ri.npages
  405.     , fmtTime((time_t) ri.time)
  406. ));
  407. addParams(msg, ri.params);
  408. break;
  409.     case Trigger::RECV_DOC:
  410. msg.append(fxStr::format("From %s (com %s), %u pages in %s, file %s"
  411.     , (const char*) ri.sender
  412.     , (const char*) ri.commid
  413.     , ri.npages
  414.     , fmtTime((time_t) ri.time)
  415.     , (const char*) ri.qfile
  416. ));
  417. break;
  418.     default:
  419. msg.append(unknownEvent);
  420. break;
  421.     }
  422.     logEventMsg(h, msg);
  423. }