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
))
30 def on_sighup(signum
, frame
):
31 '''Handle SIGHUP. This will rehash the configuration.'''
35 def on_sigint(signum
, frame
):
36 '''Handle SIGINT. This will exit gracefully.'''
38 shutdown(signum
, 'Caught SIGINT (terminal interrupt)')
40 def on_sigterm(signum
, frame
):
41 '''Handle SIGTERM. This will exit gracefully.'''
43 shutdown(signum
, 'Caught SIGTERM')
46 '''Output command line options and their meanings.'''
48 print '-c (--config) <config>: Specify the configuration file to use.'
49 print '-h (--help): Output this message.'
50 print '-n (--nofork): Do not fork into the background (will output log messages)'
51 print '-p (--pydebug): Start in the Python Debugger.'
52 print '-v (--version): Output version information.'
55 '''Our entry point.'''
59 print >> sys
.stderr
, 'synarere: will not run as root for security reasons'
62 # Parse command line options and parameter list.
64 opts
, args
= getopt
.getopt(argv
, 'c:hnpv', ['config=', 'help', 'nofork', 'pydebug', 'version'])
65 except getopt
.GetoptError
, err
:
66 print >> sys
.stderr
, '%s\n' % err
71 if opt
in ('-c', '--config'):
73 elif opt
in ('-h', '--help'):
76 elif opt
in ('-n', '--nofork'):
78 elif opt
in ('-p', '--pydebug'):
81 elif opt
in ('-v', '--version'):
82 print 'synarere: version %s' % var
.version
85 # Attach signals to handlers.
86 signal
.signal(signal
.SIGHUP
, on_sighup
)
87 signal
.signal(signal
.SIGINT
, on_sigint
)
88 signal
.signal(signal
.SIGTERM
, on_sigterm
)
89 signal
.signal(signal
.SIGPIPE
, signal
.SIG_IGN
)
90 signal
.signal(signal
.SIGALRM
, signal
.SIG_IGN
)
91 signal
.signal(signal
.SIGCHLD
, signal
.SIG_IGN
)
92 signal
.signal(signal
.SIGWINCH
, signal
.SIG_IGN
)
93 signal
.signal(signal
.SIGTTIN
, signal
.SIG_IGN
)
94 signal
.signal(signal
.SIGTTOU
, signal
.SIG_IGN
)
95 signal
.signal(signal
.SIGTSTP
, signal
.SIG_IGN
)
97 print 'synarere: version %s' % var
.version
99 # Initialize the configuration parser.
101 var
.conf
= confparse
.ConfigParser(var
.config_file
)
102 except confparse
.Exception, errstr
:
103 print >> sys
.stderr
, 'synarere: configuration error for %s: %s' % (var
.config_file
, errstr
)
104 sys
.exit(os
.EX_CONFIG
)
106 # Check to see if we are already running.
108 pid_file
= open(var
.conf
.get('options', 'pidfile')[0], 'r')
111 pid
= pid_file
.read()
121 print >> sys
.stderr
, 'synarere: an instance is already running'
122 sys
.exit(os
.EX_SOFTWARE
)
128 # Fork into the background.
133 return (e
.errno
, e
.strerror
)
135 # This is the child process.
139 # Now the child fork()'s a child in order to prevent acquisition
140 # of a controlling terminal.
144 return (e
.errno
, e
.strerror
)
146 # This is the second child process.
148 os
.chdir(os
.getcwd())
151 # This is the first child.
153 print 'synarere: pid', pid
154 print 'synarere: running in background mode from:', os
.getcwd()
159 # Try to write the PID file.
161 pid_file
= open(var
.conf
.get('options', 'pidfile')[0], 'w')
162 pid_file
.write(str(os
.getpid()))
165 print >> sys
.stderr
, 'synarere: unable to write pid file:', os
.strerror(e
.args
[0])
167 # Try to close all open file descriptors.
168 # If we cant find the max number, just close the first 256.
170 maxfd
= os
.sysconf('SC_OPEN_MAX')
171 except (AttributeError, ValueError):
174 for fd
in range(0, maxfd
):
180 # Redirect the standard file descriptors to /dev/null.
181 os
.open('/dev/null', os
.O_RDONLY
)
182 os
.open('/dev/null', os
.O_RDWR
)
183 os
.open('/dev/null', os
.O_RDWR
)
185 print 'synarere: pid', os
.getpid()
186 print 'synarere: running in foreground mode from:', os
.getcwd()
188 # Initialize the logger.
191 # These has to be in the main file.
192 command
.add('VERSION', ctcp_version
, command
.ctcp
)
193 command
.add('PING', ctcp_ping
, command
.ctcp
)
195 # Load all modules listed in the configuration.
198 # Connect to all IRC networks.
204 # This should NEVER happen.
205 shutdown(os
.EX_SOFTWARE
, 'Main loop exited (?)')
207 if __name__
== '__main__':