forked from myano/jenni
-
Notifications
You must be signed in to change notification settings - Fork 1
/
jenni
executable file
·267 lines (207 loc) · 8.21 KB
/
jenni
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
#!/usr/bin/env python
"""
jenni - An IRC Bot
Copyright 2009-2013, Michael Yanovich (yanovich.net)
Copyright 2008-2013, Sean B. Palmer (inamidst.com)
Licensed under the Eiffel Forum License 2.
More info:
* jenni: https://github.com/myano/jenni/
* Phenny: http://inamidst.com/phenny/
Note: DO NOT EDIT THIS FILE.
Run ./jenni, then edit ~/.jenni/default.py
Then run ./jenni again
"""
import sys, os, imp, optparse
from configs import Configs
from textwrap import dedent as trim
dotdir = os.path.expanduser('~/.jenni')
configpath = os.path.expanduser(dotdir + '/default.py')
if getattr(os, 'geteuid', None) and os.geteuid() == 0:
error = 'Error: Refusing to run as root.'
print >> sys.stderr, error
sys.exit(1)
def check_python_version():
if sys.version_info < (2, 4):
error = 'Error: Requires Python 2.4 or later, from www.python.org'
print >> sys.stderr, error
sys.exit(1)
def create_default_config(fn):
f = open(fn, 'w')
output = """\
# Lines that begin with a "#" are comments.
# Remove the "#" from the beginning of a line to make those lines active.
nick = 'jenni'
host = 'irc.example.net'
port = 6667
ssl = False
sasl = False
channels = ['#example', '#test']
# Channel jenni will report all private messages sent to her to.
# This includes server notices.
# logchan_pm = '#jenni-log'
# You can also specify nick@hostmask
# For example: yano@unaffiliated/yano
owner = 'yournickname'
# user is the NickServ userid
# This is useful if your NickServ user is different than the nick you are using
# user = 'userid'
# password is the NickServ password, serverpass is the server password
# password = 'example'
# serverpass = 'serverpass'
## API KEYS
# forecastio_apikey is for an API key from https://forecast.io/
# This is useful if you want extended weather information.
# Required if you want .weather to work.
# If not, you can use .weather-noaa or .wx-noaa
# forecastio_apikey = ''
# wunderground_apikey is for an API key from http://www.wunderground.com/
# This is useful if you want more local and *live* weather information.
# This is optional and doesn't need to be added.
# wunderground_apikey = ''
# google_dev_apikey is for an API key from Google Developers
# https://developers.google.com/api-client-library/python/guide/aaa_apikeys
# Get a Server API Key; this is required for YouTube to work.
# google_dev_apikey = ''
# wolframalpha_apikey is for an API key from Wolfram|Alpha
# http://products.wolframalpha.com/api/
# This is needed in order to make .calc/.c have more comprehensive answers.
# wolframalpha_apikey = ''
# twitter_consumer_key and twitter_consumer_secret are for Twitter's API
# https://apps.twitter.com/
# This is needed if you'd like to make .twitter usable
# twitter_consumer_key = ''
# twitter_consumer_secret = ''
# Fill in Yelp API information here
# This is for using the .food command
yelp_api_credentials = {
'consumer_key': '',
'consumer_secret': '',
'token': '',
'token_secret': ''
}
# You can add bannable words / regex per channel
# bad_words = {
# "#yourchan": ['badword', '(a|b).*c.*(d|e)']
# }
#
# This controls the number of warnings a user will receive
# before they are banned from the channel
# bad_word_limit = 1
# auto_title_disable_chans is for disabling the auto URL title feature
# simply add a channel to this list (preferably in all lower-case)
# and it won't auto-title URLs in that channel, but .title and other features
# will still work
# auto_title_disable_chans = ['##yano',]
# These are people who will be able to use admin.py's functions...
admins = [owner, 'someoneyoutrust']
# But admin.py is disabled by default, as follows:
exclude = ['adminchannel', 'chicken_reply', 'insult', 'lispy', 'twss']
# This allows one to allow specific people to use ".msg channel message here"
# in specific channels.
helpers = {
'#channel1': ['a.somedomain.tld', 'b.anotherdomain.tld'],
'##channel2': ['some/other/hostmask'],
}
# Enable raw logging of everything jenni sees.
# logged to the folder 'log'
logging = False
# Block modules from specific channels
# To not block anything for a channel, just don't mention it
excludes = {
'##blacklist': ['!'],
}
# If you want to enumerate a list of modules rather than disabling
# some, use "enable = ['example']", which takes precedent over exclude
#
# enable = []
# Directories to load user modules from
# e.g. /path/to/my/modules
extra = ['""" + os.getcwd() + '/modules/' + """']
# Services to load: maps channel names to white or black lists
external = {
'#liberal': ['!'], # allow all
'#conservative': [], # allow none
'*': ['!'] # default whitelist, allow all
}
# insult database available: "spanish" and "english"
insult_lang = "english"
# EOF
"""
print >> f, trim(output)
f.close()
def create_configfile(dotdir):
if not os.path.isdir(dotdir):
print 'Creating a config directory at ~/.jenni...'
try: os.mkdir(dotdir)
except Exception, e:
print >> sys.stderr, 'There was a problem creating %s:' % dotdir
print >> sys.stderr, e.__class__, str(e)
print >> sys.stderr, 'Please fix this and then run jenni again.'
sys.exit(1)
create_default_config(configpath)
print >> sys.stdout, 'Config file generated. Please edit it at ' + configpath + ' and run ./jenni again.'
sys.exit(0)
def check_dotdir():
if not os.path.isdir(dotdir) or not os.path.isfile(configpath):
create_configfile(dotdir)
def config_names(config):
config = config or 'default'
def files(d):
names = os.listdir(d)
return list(os.path.join(d, fn) for fn in names if fn.endswith('.py'))
here = os.path.join('.', config)
if os.path.isfile(here):
return [here]
if os.path.isfile(here + '.py'):
return [here + '.py']
if os.path.isdir(here):
here_files = files(here)
if(len(here_files) == 0):
print >> sys.stderr, "Error: Config directory '{0}' contained no .py files".format(here)
return here_files
there = os.path.join(dotdir, config)
if os.path.isfile(there):
return [there]
if os.path.isfile(there + '.py'):
return [there + '.py']
if os.path.isdir(there):
there_files = files(there)
if(len(there_files) == 0):
print >> sys.stderr, "Error: Config directory '{0}' contained no .py files".format(there)
return there_files
print >> sys.stderr, "Error: Couldn't find config '{0}' to import or .py files therein".format(config)
sys.exit(1)
def initialize_configs(config_path):
config_modules = []
all_configs = config_names(config_path)
if(len(all_configs) == 0):
print >> sys.stderr, "Error: no config files found in config path '{0}'".format(config_path)
sys.exit(1)
config_helper = Configs(all_configs)
config_helper.load_modules(config_modules)
# Give at least one module the config helper
config_modules[0].config_helper = config_helper
# Step Four: Load jenni
try: from __init__ import run
except ImportError:
try: from jenni import run
except ImportError:
print >> sys.stderr, "Error: Couldn't find jenni to import"
sys.exit(1)
# Step Five: Initialise And Run The jennies
# @@ ignore SIGHUP
for config_module in config_modules:
run(config_module) # @@ thread this
def main(argv=None):
# Step One: Parse The Command Line
parser = optparse.OptionParser('%prog [options]')
parser.add_option('-c', '--config', metavar='fn',
help='use this configuration file or directory')
opts, args = parser.parse_args(argv)
# Step Two: Check Dependencies
check_python_version() # require python2.4 or later
check_dotdir() # require ~/.jenni, or make it and exit
# Step Three: Load The Configurations
initialize_configs(opts.config)
if __name__ == '__main__':
main()