⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 smsd.py

📁 Network Administration Visualized 网络管理可视化源码
💻 PY
字号:
#! /usr/bin/env python# -*- coding: utf-8 -*-## Copyright 2006 UNINETT AS## This file is part of Network Administration Visualized (NAV)## NAV is free software; you can redistribute it and/or modify# it under the terms of the GNU General Public License as published by# the Free Software Foundation; either version 2 of the License, or# (at your option) any later version.## NAV is distributed in the hope that it will be useful,# but WITHOUT ANY WARRANTY; without even the implied warranty of# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the# GNU General Public License for more details.## You should have received a copy of the GNU General Public License# along with NAV; if not, write to the Free Software# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA## Authors: Stein Magnus Jodal <stein.magnus.jodal@uninett.no>#"""The NAV SMS daemon (smsd)smsd dispatches SMS messages from the database to users' phones with the helpof plugins using Gammu and a cell on the COM port, or free SMS services on theweb.Usage: smsd [-h] [-c] [-d sec] [-t phone no.]  -h, --help            Show this help text  -c, --cancel          Cancel (mark as ignored) all unsent messages  -d, --delay           Set delay (in seconds) between queue checks  -t, --test            Send a test message to <phone no.>"""__copyright__ = "Copyright 2006 UNINETT AS"__license__ = "GPL"__author__ = "Stein Magnus Jodal (stein.magnus.jodal@uninett.no)"__id__ = "$Id: smsd.py 3963 2007-04-12 08:58:37Z mortenv $"import atexitimport ConfigParser # parts require Python >= 2.3import emailimport getoptimport logging # require Python >= 2.3import logging.handlers # require Python >= 2.3import osimport os.pathimport pwdimport smtplibimport socketimport sysimport timeimport signalimport nav.configimport nav.daemonimport nav.logsimport nav.pathimport nav.smsd.navdbqueuefrom nav.smsd.dispatcher import DispatcherError, PermanentDispatcherError# Dispatchers are imported later according to config### PATHSconfigfile = os.path.join(nav.path.sysconfdir, 'smsd.conf')logfile = os.path.join(nav.path.localstatedir, 'log', 'smsd.log')pidfile = os.path.join(nav.path.localstatedir, 'run', 'smsd.pid')### MAIN FUNCTIONdef main(args):    # Get command line arguments    optcancel = False    optdelay = False    opttest = False    try:        opts, args = getopt.getopt(args, 'hcd:t:',         ['help', 'cancel', 'delay=', 'test='])    except getopt.GetoptError, error:        print >> sys.stderr, "%s\nTry `%s --help' for more information." % \         (error, sys.argv[0])        sys.exit(1)    for opt, val in opts:        if opt in ('-h', '--help'):            usage()            sys.exit(0)        if opt in ('-c', '--cancel'):            optcancel = True        if opt in ('-d', '--delay'):            optdelay = val        if opt in ('-t', '--test'):            opttest = val    # Set config defaults    defaults = {        'username': 'navcron',        'delay': '30',        'autocancel': '0',        'loglevel': 'INFO',        'mailwarnlevel': 'ERROR',        'mailserver': 'localhost',        'mailaddr': nav.config.readConfig('nav.conf')['ADMIN_MAIL']    }    # Read config file    config = getconfig(defaults)    # Set variables    username = config['main']['username']    delay = int(config['main']['delay'])    autocancel = config['main']['autocancel']    loglevel = eval('logging.' + config['main']['loglevel'])    mailwarnlevel = eval('logging.' + config['main']['mailwarnlevel'])    mailserver = config['main']['mailserver']    mailaddr = config['main']['mailaddr']    # Initialize logger    global logger    logger = logging.getLogger('nav.smsd')    logger.setLevel(1) # Let all info through to the root node    loginitstderr(loglevel)    # Set custom loop delay    if optdelay:        setdelay(optdelay)    # Ignore unsent messages    if optcancel:        queue = nav.smsd.navdbqueue.NAVDBQueue()        ignCount = queue.cancel()        logger.info("All %d unsent messages ignored.", ignCount)        sys.exit(0)    # Let the dispatcherhandler take care of our dispatchers    dh = nav.smsd.dispatcher.DispatcherHandler(config)     # Send test message (in other words: test the dispatcher)    if opttest:        msg = [(0, "This is a test message from NAV smsd.", 0)]        try:            (sms, sent, ignored, smsid) = dh.sendsms(opttest, msg)        except DispatcherError, error:            logger.critical("Sending failed. Exiting. (%s)", error)            sys.exit(1)        logger.info("SMS sent. Dispatcher returned reference %d.", smsid)        sys.exit(0)    # Switch user to navcron (only works if we're root)    try:        nav.daemon.switchuser(username)    except nav.daemon.DaemonError, error:        logger.error("%s Run as root or %s to enter daemon mode. " \         + "Try `%s --help' for more information.",         error, username, sys.argv[0])        sys.exit(1)    # Init daemon loggers    if not loginitfile(loglevel, logfile):        sys.exit(1)    if not loginitsmtp(mailwarnlevel, mailaddr, mailserver):        sys.exit(1)    # Check if already running    try:        nav.daemon.justme(pidfile)    except nav.daemon.DaemonError, error:        logger.error(error)        sys.exit(1)    # Daemonize    try:        nav.daemon.daemonize(pidfile)    except nav.daemon.DaemonError, error:        logger.error(error)        sys.exit(1)    # Reopen log files on SIGHUP    signal.signal(signal.SIGHUP, signalhandler)    # Initialize queue    # NOTE: If we're initalizing a queue with a DB connection before    # daemonizing we've experienced that the daemon dies silently upon trying    # to use the DB connection after becoming a daemon    queue = nav.smsd.navdbqueue.NAVDBQueue()    # Automatically cancel unsent messages older than a given interval    if autocancel != '0':        ignCount = queue.cancel(autocancel)        logger.info("%d unsent messages older than '%s' autocanceled.",                    ignCount, autocancel)    # Loop forever    while True:        logger.debug("Starting loop.")        # Queue: Get users with unsent messages        users = queue.getusers('N')        logger.info("Found %d user(s) with unsent messages.", len(users))        # Loop over cell numbers        for user in users:            # Queue: Get unsent messages for a user ordered by severity desc            msgs = queue.getusermsgs(user, 'N')            logger.info("Found %d unsent message(s) for %s.",             len(msgs), user)            # Dispatcher: Format and send SMS            try:                (sms, sent, ignored, smsid) = dh.sendsms(user, msgs)            except PermanentDispatcherError, error:                logger.critical("Sending failed permanently. Exiting. (%s)",                                error)                sys.exit(1)            except DispatcherError, error:                logger.critical("Sending failed. (%s)", error)                break # End this run            except Exception, error:                logger.exception("Unknown exception: %s", error)            logger.info("SMS sent to %s.", user)            for msgid in sent:                queue.setsentstatus(msgid, 'Y', smsid)            for msgid in ignored:                queue.setsentstatus(msgid, 'I', smsid)            logger.info("%d messages was sent and %d ignored.",             len(sent), len(ignored))        # Sleep a bit before the next run        logger.debug("Sleeping for %d seconds.", delay)        time.sleep(delay)        # Devel only        #break    # Exit nicely    sys.exit(0)def signalhandler(signum, frame):    """    Signal handler to close and reopen log file(s) on HUP.    """    if signum == signal.SIGHUP:        logger.info("SIGHUP received; reopening log files")        nav.logs.reopen_log_files()        logger.info("Log files reopened")### INIT FUNCTIONSdef getconfig(defaults = None):    """    Read whole config from file.        Arguments:        ``defaults'' are passed on to configparser before reading config.        Returns:        Returns a dict, with sections names as keys and a dict for each        section as values.    """    config = ConfigParser.SafeConfigParser(defaults)    config.read(configfile)    sections = config.sections()    configdict = {}    for section in sections:        configsection = config.items(section)        sectiondict = {}        for opt, val in configsection:            sectiondict[opt] = val        configdict[section] = sectiondict    return configdictdef loginitfile(loglevel, logfile):    """Initalize the logging handler for logfile."""    try:        filehandler = logging.FileHandler(logfile, 'a')        fileformat = '[%(asctime)s] [%(levelname)s] [pid=%(process)d %(name)s] %(message)s'        fileformatter = logging.Formatter(fileformat)        filehandler.setFormatter(fileformatter)        filehandler.setLevel(loglevel)        logger = logging.getLogger()        logger.addHandler(filehandler)        return True    except IOError, error:        print >> sys.stderr, \         "Failed creating file loghandler. Daemon mode disabled. (%s)" \         % error        return Falsedef loginitstderr(loglevel):    """Initalize the logging handler for stderr."""    try:        stderrhandler = logging.StreamHandler(sys.stderr)        stderrformat = '%(levelname)s %(message)s'        stderrformatter = logging.Formatter(stderrformat)        stderrhandler.setFormatter(stderrformatter)        stderrhandler.setLevel(loglevel)        logger = logging.getLogger()        logger.addHandler(stderrhandler)        return True    except IOError, error:        print >> sys.stderr, \         "Failed creating stderr loghandler. Daemon mode disabled. (%s)" \         % error        return Falsedef loginitsmtp(loglevel, mailaddr, mailserver):    """Initalize the logging handler for SMTP."""    try:        # localuser will be root if smsd was started as root, since        # switchuser() is first called at a later time        localuser = pwd.getpwuid(os.getuid())[0]        hostname = socket.gethostname()        fromaddr = localuser + '@' + hostname        mailhandler = logging.handlers.SMTPHandler(mailserver, fromaddr,         mailaddr, 'NAV smsd warning from ' + hostname)        mailformat = '[%(asctime)s] [%(levelname)s] [pid=%(process)d %(name)s] %(message)s'        mailformatter = logging.Formatter(mailformat)        mailhandler.setFormatter(mailformatter)        mailhandler.setLevel(loglevel)        logger = logging.getLogger()        logger.addHandler(mailhandler)        return True    except Exception, error:        print >> sys.stderr, \         "Failed creating SMTP loghandler. Daemon mode disabled. (%s)" \         % error        return Falsedef usage():    """Print a usage screen to stderr."""    print >> sys.stderr, __doc__def setdelay(sec):    """Set delay (in seconds) between queue checks."""    global delay    if sec.isdigit():        sec = int(sec)        delay = sec        logger.info("Setting delay to %d seconds.", sec)        return True    else:        logger.warning("Given delay not a digit. Using default.")        return False### BEGINif __name__ == '__main__':    main(sys.argv[1:])

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -