SNPPServer.c++
上传用户:weiyuanprp
上传日期:2020-05-20
资源大小:1169k
文件大小:40k
- /* $Id: SNPPServer.c++,v 1.8 2008/04/26 22:34:29 faxguy 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.
- */
- #ifdef SNPP_SUPPORT
- /*
- * Simple Network Paging Protocol (SNPP) Support.
- */
- #include "config.h"
- #include "Sys.h"
- #include "Socket.h"
- #include "SNPPServer.h"
- #include "Dispatcher.h"
- #include "RE.h"
- #include <ctype.h>
- #if HAS_CRYPT_H
- #include <crypt.h>
- #endif
- extern "C" {
- #include <netdb.h>
- #include <arpa/inet.h>
- #include <netinet/in_systm.h>
- #include <netinet/ip.h>
- }
- SNPPSuperServer::SNPPSuperServer(const char* p, int bl)
- : SuperServer("SNPP", bl)
- , port(p)
- {}
- SNPPSuperServer::~SNPPSuperServer() {}
- bool
- SNPPSuperServer::startServer(void)
- {
- /*
- * Switch to super-user to do the bind in case
- * we are to use a port in the privileged region
- * on a BSD system (ports <=1024 are reserved
- * and the default SNPP port is 444).
- *
- * NB: We do it for both the socket+bind calls
- * to workaround a bug in Solaris 2.5.
- */
- uid_t ouid = geteuid();
- (void) seteuid(0);
- int s = socket(AF_INET, SOCK_STREAM, 0);
- if (s >= 0) {
- struct sockaddr_in sin;
- memset(&sin, 0, sizeof (sin));
- sin.sin_family = AF_INET;
- const char* cp = port;
- struct servent* sp = getservbyname(cp, SNPP_PROTONAME);
- if (!sp) {
- if (isdigit(cp[0]))
- sin.sin_port = htons(atoi(cp));
- else
- sin.sin_port = htons(SNPP_DEFPORT);
- } else
- sin.sin_port = sp->s_port;
- if (Socket::bind(s, &sin, sizeof (sin)) >= 0) {
- (void) listen(s, getBacklog());
- (void) seteuid(ouid);
- Dispatcher::instance().link(s, Dispatcher::ReadMask, this);
- return (true); // success
- }
- Sys::close(s);
- logError("HylaFAX %s: bind (port %u): %m",
- getKind(), ntohs(sin.sin_port));
- } else
- logError("HylaFAX %s: socket: %m", getKind());
- (void) seteuid(ouid);
- return (false);
- }
- HylaFAXServer* SNPPSuperServer::newChild(void) { return new SNPPServer; }
- SNPPServer::SNPPServer() {}
- SNPPServer::~SNPPServer() {}
- void
- SNPPServer::open(void)
- {
- setupNetwork(STDIN_FILENO);
- initServer(); // complete state initialization
- fxStr emsg;
- if (!initClientFIFO(emsg)) {
- logInfo("connection refused (%s) from %s [%s]",
- (const char*) emsg,
- (const char*) remotehost, (const char*) remoteaddr);
- reply(420, "%s server cannot initialize: %s",
- (const char*) hostname, (const char*) emsg);
- dologout(-1);
- }
- ctrlFlags = fcntl(STDIN_FILENO, F_GETFL); // for parser
- if (isShutdown(true)) {
- reply(421, "%s SNPP server unavailable; try again later.",
- (const char*) hostname);
- dologout(-1);
- }
- reply(220, "%s SNPP server (%s) ready.", (const char*) hostname, version);
- if (TRACE(CONNECT))
- logInfo("SNPP connection from %s [%s]",
- (const char*) remotehost, (const char*) remoteaddr);
- }
- void
- SNPPServer::initServer(void)
- {
- InetFaxServer::initServer();
- state &= ~S_USEGMT; // SNPP uses local times
- resetState();
- }
- void
- SNPPServer::initDefaultJob(void)
- {
- InetFaxServer::initDefaultJob();
- defJob.jobtype = "pager";
- initSNPPJob();
- }
- void
- SNPPServer::initSNPPJob(void)
- {
- defJob.queued = false; // jobs not queued--per protocol
- defJob.maxdials = SNPP_DEFREDIALS; // configuration defaults...
- defJob.maxtries = SNPP_DEFRETRIES;
- defJob.killtime = 60*killMap[SNPP_DEFLEVEL];
- defJob.retrytime = retryMap[SNPP_DEFLEVEL];
- defJob.usrpri = priMap[SNPP_DEFLEVEL];
- // XXX default notification
- }
- void
- SNPPServer::resetState(void)
- {
- initDefaultJob(); // default job state
- msgFile = "";
- haveText = false; // no message text yet
- msgs.resize(0); // purge any message refs
- }
- void
- SNPPServer::dologout(int status)
- {
- /*
- * Purge any partially constructed jobs. If we were
- * doing a SEND when the connection was dropped then
- * we do not purge jobs but instead just let them run
- * detached. This may not be the best thing; we might
- * instead want to kill the jobs--we'll need to think
- * about this some more before changing this behaviour.
- */
- if (msgs.length() > 0 && !IS(SENDWAIT)) {
- fxStr emsg;
- for (u_int i = 0, n = msgs.length(); i < n; i++) {
- Job* job = findJob(msgs[i], emsg);
- if (job) {
- for (u_int j = 0, m = job->items.length(); j < m; j++)
- if (job->items[j].op == FaxRequest::send_data)
- (void) Sys::unlink(job->items[j].item);
- (void) Sys::unlink(job->qfile);
- delete job;
- }
- }
- }
- InetFaxServer::dologout(status);
- }
- static inline bool
- isMagic(char c)
- {
- return (c == '[' || c == ']' || c == '*' || c == '.' || c == '^' ||
- c == '$' || c == '-' || c == '+' || c == '{' || c == '}' ||
- c == '(' || c == ')');
- }
- /*
- * Handle escapes for a pager ID replacement string.
- */
- static void
- subRHS(fxStr& result, const RE& re, const fxStr& match)
- {
- /*
- * Do ``&'' and ``n'' interpolations in the replacement.
- */
- for (u_int i = 0, n = result.length(); i < n; i++) {
- if (result[i] == '\') { // process <char> escapes
- result.remove(i), n--;
- if (isdigit(result[i])) {
- int mn = result[i] - '0';
- int ms = re.StartOfMatch(mn);
- int mlen = re.EndOfMatch(mn) - ms;
- result.remove(i); // delete n
- if (ms >= 0)
- result.insert(match.extract(ms, mlen), i);
- else
- logError("Invalid backreference in pagermap: \%d", mn);
- n = result.length(); // adjust string length ...
- i += mlen - 1; // ... and scan index
- }
- } else if (result[i] == '&') { // process & replacement
- int ms = re.StartOfMatch(0);
- int mlen = re.EndOfMatch(0) - ms;
- result.remove(i); // delete &
- result.insert(match.extract(ms, mlen), i);
- n = result.length(); // adjust string length ...
- i += mlen - 1; // ... and scan index
- }
- }
- }
- /*
- * Given a client-supplied pager ID return the phone number
- * to dial of the service provider and the PIN to supply
- * to the provider when talking IXO/TAP (for aliases).
- */
- bool
- SNPPServer::mapPagerID(const char* pagerID, fxStr& number, fxStr& pin, fxStr& emsg)
- {
- if (pagerIDMapFile != "") {
- FILE* fd = fopen(fixPathname(pagerIDMapFile), "r");
- if (fd != NULL) {
- char buf[1024];
- while (fgets(buf, sizeof (buf), fd)) {
- char* cp;
- for (cp = buf; isspace(*cp); cp++) // leading whitespace
- ;
- if (*cp == '#' || *cp == ' ')
- continue;
- /*
- * Syntax is:
- *
- * <pattern> <dialstring>[/<PIN>]
- *
- * where <pattern> can be a simple string of alpha
- * numerics or a regular expression. The first line
- * that matches the client-specified pager ID is used.
- * If no <PIN> is specified then the client-specified
- * string is sent to the provider. If <dialstring>
- * is "reject" (verbatim) then matches are rejected.
- * <PIN> is treated as the RHS of an RE-style substitution:
- * n and & escapes are replaced according to the RE
- * matching work.
- *
- * Leading white space on a line is ignored. Lines
- * that begin with '#' are ignored (i.e. comments).
- */
- const char* pattern = cp;
- bool isRE = false;
- for (; *cp != ' ' && !isspace(*cp); cp++)
- if (isMagic(*cp))
- isRE = true;
- if (*cp != ' ') //