3 # synarere -- a highly modular and stable IRC bot.
4 # Copyright (C) 2010 Michael Rodriguez.
5 # Rights to this code are documented in docs/LICENSE.
7 '''Main program. This does basic routines, and calls core functions.'''
9 # Import required Python modules.
10 import getopt
, os
, signal
, sys
12 # Import required core modules.
13 from core
import module
, irc
, logger
, io
, var
, confparse
, command
15 # Import required core function.
16 from core
import shutdown
18 def ctcp_version(conn
, (nick
, user
, host
), message
):
19 '''Handle VERSION requests.'''
21 conn
.sendq
.appendleft('NOTICE %s :\001VERSION synarere-%s\001' % (nick
, var
.version
))
24 def ctcp_ping(conn
, (nick
, user
, host
), message
):
25 '''Handle PING requests.'''
27 conn
.sendq
.appendleft('NOTICE %s :\001PING %s\001' % (nick
, message
))
31 '''Output command line options and their meanings.'''
33 print '-c (--config) <config>: Specify the configuration file to use.'
34 print '-h (--help): Output this message.'
35 print '-n (--nofork): Do not fork into the background (will output log messages)'
36 print '-p (--pydebug): Start in the Python Debugger.'
37 print '-v (--version): Output version information.'
39 def main(argv
=sys
.argv
[1:]):
40 '''Our entry point.'''
44 print >> sys
.stderr
, 'synarere: will not run as root for security reasons'
47 # Parse command line options and parameter list.
49 opts
, args
= getopt
.getopt(argv
, 'c:hnpv', ['config=', 'help', 'nofork', 'pydebug', 'version'])
50 except getopt
.GetoptError
, err
:
51 print >> sys
.stderr
, '%s\n' % err
56 if opt
in ('-c', '--config'):
58 elif opt
in ('-h', '--help'):
61 elif opt
in ('-n', '--nofork'):
63 elif opt
in ('-p', '--pydebug'):
66 elif opt
in ('-v', '--version'):
67 print 'synarere: version %s' % var
.version
70 # Attach signals to handlers.
71 signal
.signal(signal
.SIGHUP
, lambda h
: var
.conf
.rehash(True))
72 signal
.signal(signal
.SIGINT
, lambda i
: shutdown(signal
.SIGINT
, 'Caught SIGINT (terminal interrupt)'))
73 signal
.signal(signal
.SIGTERM
, lambda t
: shutdown(signal
.SIGTERM
, 'Caught SIGTERM'))
74 signal
.signal(signal
.SIGPIPE
, signal
.SIG_IGN
)
75 signal
.signal(signal
.SIGALRM
, signal
.SIG_IGN
)
76 signal
.signal(signal
.SIGCHLD
, signal
.SIG_IGN
)
77 signal
.signal(signal
.SIGWINCH
, signal
.SIG_IGN
)
78 signal
.signal(signal
.SIGTTIN
, signal
.SIG_IGN
)
79 signal
.signal(signal
.SIGTTOU
, signal
.SIG_IGN
)
80 signal
.signal(signal
.SIGTSTP
, signal
.SIG_IGN
)
82 print 'synarere: version %s' % var
.version
84 # Initialize the configuration parser.
86 var
.conf
= confparse
.ConfigParser(var
.config_file
)
87 except confparse
.Exception, errstr
:
88 print >> sys
.stderr
, 'synarere: configuration error for %s: %s' % (var
.config_file
, errstr
)
89 sys
.exit(os
.EX_CONFIG
)
91 # Check to see if we are already running.
93 pid_file
= open(var
.conf
.get('options', 'pidfile')[0], 'r')
106 print >> sys
.stderr
, 'synarere: an instance is already running'
107 sys
.exit(os
.EX_SOFTWARE
)
113 # Fork into the background.
118 return (e
.errno
, e
.strerror
)
120 # This is the child process.
124 # Now the child fork()'s a child in order to prevent acquisition
125 # of a controlling terminal.
129 return (e
.errno
, e
.strerror
)
131 # This is the second child process.
133 os
.chdir(os
.getcwd())
136 # This is the first child.
138 print 'synarere: pid', pid
139 print 'synarere: running in background mode from:', os
.getcwd()
144 # Try to write the PID file.
146 pid_file
= open(var
.conf
.get('options', 'pidfile')[0], 'w')
147 pid_file
.write(str(os
.getpid()))
150 print >> sys
.stderr
, 'synarere: unable to write pid file:', os
.strerror(e
.args
[0])
152 # Try to close all open file descriptors.
153 # If we cant find the max number, just close the first 256.
155 maxfd
= os
.sysconf('SC_OPEN_MAX')
156 except (AttributeError, ValueError):
159 for fd
in range(0, maxfd
):
165 # Redirect the standard file descriptors to /dev/null.
166 os
.open('/dev/null', os
.O_RDONLY
)
167 os
.open('/dev/null', os
.O_RDWR
)
168 os
.open('/dev/null', os
.O_RDWR
)
170 print 'synarere: pid', os
.getpid()
171 print 'synarere: running in foreground mode from:', os
.getcwd()
173 # Initialize the logger.
176 # These have to be in the main file.
177 command
.add('VERSION', ctcp_version
, command
.ctcp
)
178 command
.add('PING', ctcp_ping
, command
.ctcp
)
180 # Load all modules listed in the configuration.
183 # Connect to all IRC networks.
189 # This should NEVER happen.
190 shutdown(os
.EX_SOFTWARE
, 'Main loop exited (?)')
192 if __name__
== '__main__':