2 from __future__
import generators
3 import html
, re
, irclib
, ircbot
, thread
, sys
, atexit
, bz2
, logging
, traceback
, time
, threadsafe_sched
, os
4 from dateutil
.parser
import parse
as raw_time_parser
5 from cPickle
import dumps
as pickle
, loads
as depickle
10 hal
= ircbot
.SingleServerIRCBot([("localhost", 6667)], nick
, "Halbot")
11 hal
.connect("localhost", 6667, nick
)
13 hal
.connection
.join("#casualgameplay")
14 hal
.connection
.privmsg("NickServ", "identify Orqv)>y!")
15 is_re
= re
.compile(" (is|are|was|were)( |$)", re
.IGNORECASE
)
16 nick_re
= re
.compile(nick
+ "[:,] ", re
.IGNORECASE
)
18 scheduler
= threadsafe_sched
.scheduler()
19 os
.environ
['TZ'] = "GMT"
25 def __init__(self
, level
, symbol
=None):
29 Perms
.symbols
[symbol
] = self
30 def __cmp__(self
, other
):
31 return self
.level
- other
.level
36 return str(self
.level
)
38 def from_symbol(symbol
):
39 return Perms
.symbols
.get(symbol
, Perms
.present
)
40 from_symbol
= staticmethod(from_symbol
)
42 Perms
.none
= Perms(-1)
43 Perms
.present
= Perms(0)
44 Perms
.voice
= Perms(1, "+")
45 Perms
.hop
= Perms(2, "%")
46 Perms
.op
= Perms(3, "@")
47 Perms
.admin
= Perms(4, "&")
48 Perms
.owner
= Perms(5, "~")
49 Perms
.ircop
= Perms(6)
51 my_users
= ircbot
.IRCDict()
52 factoid_dbs
= ircbot
.IRCDict()
53 locked_dbs
= ircbot
.IRCDict()
54 reminder_dbs
= ircbot
.IRCDict()
55 subscription_dbs
= ircbot
.IRCDict()
59 pickled
= bz2
.decompress(zipped
)
60 (version
, data
) = depickle(pickled
)
61 if version
== SAVE_VERSION
:
62 (my_users
, factoid_dbs
, locked_dbs
, reminder_dbs
, subscription_dbs
) = data
64 (my_users
, factoid_dbs
, locked_dbs
, reminder_dbs
) = data
66 sys
.exit("Unrecognized database version.")
68 del db
, zipped
, pickled
72 logging
.getLogger().addHandler(logging
.FileHandler("error.log"))
75 def __init__(self
, prefix
=""):
77 def write(self
, unbuffered
):
78 self
.data
+= unbuffered
80 def get_timestamp(when
=None):
83 return time
.ctime(when
) + " " + time
.tzname
[time
.daylight
]
85 def parse_time(time_string
):
86 return time
.mktime(raw_time_parser(time_string
).timetuple())
88 def safe_call(func
, args
):
92 if isinstance(e
, SystemExit):
94 buffer = Buffer("Exception in function %s at %s:\n"
95 % (func
.__name
__, get_timestamp()))
96 traceback
.print_exc(file=buffer)
97 logging
.getLogger().error(buffer.data
)
98 # Try to report the error interactively.
99 if len(args
) >= 2 and type(args
[0]) == type(args
[1]) == str:
101 reply(args
[0], args
[1], "Ow! Ohh, man, that didn't feel good. " \
102 +"Somebody get FunnyMan, quick!")
105 elif len(args
) and type(args
[0]) == str:
107 reply('', args
[0], "Ow! Ohh, man, that didn't feel good. " \
108 +"Somebody get FunnyMan, quick!", all
=True)
113 return lambda *args
: safe_call(func
, args
)
116 def continue_if_no_troggie(who
, where
, *args
, **kwargs
):
117 if where
in hal
.channels
:
118 chan
= hal
.channels
[where
]
119 if "troggie" not in chan
.userdict
:
120 func(who
, where
, *args
, **kwargs
)
121 return continue_if_no_troggie
123 def resize(list_or_tuple
, length
):
124 '''Creates a new list or tuple of length 'length', using as many elements from
125 list_or_tuple as possible and right-padding with "". Does not modify
127 if len(list_or_tuple
) < length
:
128 if type(list_or_tuple
) == list:
129 return list_or_tuple
+ [""] * (length
- len(list_or_tuple
))
131 return list_or_tuple
+ ("",) * (length
- len(list_or_tuple
))
133 return list_or_tuple
[:length
]
141 self
.channel_perms
= {}
143 waiting_commands
= {}
146 def got_command(who
, where
, command
, args
=""):
147 if not command
in commands
:
148 command
= 'raise error'
149 args
= "I don't understand that."
150 waiting
= waiting_commands
.get(who
, [])
152 (required_perms
, do_it
) = commands
[command
]
153 if where
== private
and required_perms
<= Perms
.owner
:
154 safe_call(do_it
, (who
, where
, args
))
155 elif required_perms
<= Perms
.voice
and where
in hal
.channels
:
156 chan
= hal
.channels
[where
]
157 if who
in chan
.voiceddict
or who
in chan
.hopdict
or who
in chan
.operdict \
158 or who
in chan
.admindict
or who
in chan
.ownerdict
:
159 safe_call(do_it
, (who
, where
, args
))
163 waiting_commands
[who
] = [(where
, command
, args
)]
164 hal
.connection
.whois((who
,))
166 waiting
.append((where
, command
, args
))
168 def reply(who
, where
, what
, all
=False):
170 hal
.connection
.privmsg(who
, what
)
172 hal
.connection
.privmsg(where
, what
)
174 hal
.connection
.privmsg(where
, "%s: %s" % (who
, what
))
176 def get_perms(who
, where
):
177 user
= whois_info
[who
]
181 server_perm
= Perms
.owner
183 server_perm
= whois_info
[who
].channel_perms
.get(where
, Perms
.none
)
185 my_perm
= my_users
.get(who
, Perms
.none
)
188 return max(server_perm
, my_perm
)
192 commands
['raise error'] = (Perms
.voice
, reply
)
194 def ping(who
, where
, args
):
195 reply(who
, where
, "Pong!")
196 commands
['ping'] = (Perms
.voice
, ping
)
198 class TestException(Exception): pass
200 def error(who
, where
, args
):
201 raise TestException
, str(args
)
202 commands
['error'] = (Perms
.ircop
, error
)
204 def join(who
, where
, args
):
205 hal
.connection
.join(where
)
206 commands
['do join'] = (Perms
.op
, join
)
208 def save(who
=None, where
=None, args
=None):
211 (my_users
, factoid_dbs
, locked_dbs
, reminder_dbs
,
214 zipped
= bz2
.compress(pickled
)
215 db
= open("hal.db", "w")
219 reply(who
, where
, "Database saved.")
220 commands
['save'] = (Perms
.ircop
, save
)
221 atexit
.register(save
)
223 def shutdown(who
, where
, args
):
224 hal
.connection
.quit("Daisy, daaaisy...")
226 commands
['shutdown'] = (Perms
.ircop
, shutdown
)
228 def title(who
, where
, args
, all
=False):
230 reply(who
, where
, "[%s]" % (html
.get_title(args
)), all
)
233 reply(who
, where
, "Error retrieving URL '%s'." % args
, all
)
234 title
= troggie(title
)
235 commands
['title'] = (Perms
.voice
, title
)
237 def title_implicit(who
, where
, args
):
238 title(who
, where
, args
, all
=True)
239 commands
['title implicit'] = (Perms
.voice
, title_implicit
)
241 def calc(who
, where
, args
):
243 reply(who
, where
, "Google says: %s" % html
.google_calc(args
), all
=True)
246 reply(who
, where
, "Ewwww... Google barfed on me.", all
=True)
247 #calc = troggie(calc)
248 commands
['calc'] = (Perms
.voice
, calc
)
250 def google(who
, where
, args
):
252 url
= html
.first_google(args
)
253 reply(who
, where
, "Google says: %s [%s]." % (url
, html
.get_title(url
)), all
=True)
256 reply(who
, where
, "Ewwww... Google barfed on me.", all
=True)
257 #google = troggie(google)
258 commands
['google'] = (Perms
.voice
, google
)
260 def jig(who
, where
, args
):
261 google(who
, where
, args
+ " site:jayisgames.com")
263 commands
['jig'] = (Perms
.voice
, jig
)
265 def wp(who
, where
, args
):
266 google(who
, where
, args
+ " site:en.wikipedia.org")
267 commands
['wp'] = (Perms
.voice
, wp
)
268 commands
['wikipedia'] = (Perms
.voice
, wp
)
270 def weather(who
, where
, args
):
271 reply(who
, where
, "I'm sorry, troggie isn't here, and I don't know how to do that.")
272 weather
= troggie(weather
)
273 commands
['weather'] = (Perms
.voice
, weather
)
275 weak_mask_re
= re
.compile(".+!.+@.+")
277 def ignore(who
, where
, args
):
278 if args
.lower().strip() == "list":
279 banlist
= ", ".join([user
for user
in my_users
if my_users
[user
] == Perms
.ban
])
280 reply(who
, where
, "Currently ignoring: %s" % banlist
)
282 if not weak_mask_re
.search(args
):
283 reply(who
, where
, "Please give a full nick!user@host mask.")
285 my_users
[args
] = Perms
.ban
286 reply(who
, where
, "Done.")
287 commands
['ignore'] = (Perms
.ircop
, ignore
)
289 def unignore(who
, where
, args
):
290 if args
in my_users
and my_users
[args
] == Perms
.ban
:
291 my_users
[args
] = Perms
.none
292 reply(who
, where
, "Done.")
294 reply(who
, where
, "I wasn't ignoring them.")
295 commands
['unignore'] = (Perms
.ircop
, unignore
)
297 def extract_my_db(dbs
, who
, where
, default_maker
):
303 default
= default_maker()
307 def get_fact_dbs(who
, where
):
308 factoids
= extract_my_db(factoid_dbs
, who
, where
, ircbot
.IRCDict
)
309 locked
= extract_my_db(locked_dbs
, who
, where
, ircbot
.IRCDict
)
310 return (factoids
, locked
)
312 def do_is(who
, where
, args
):
313 (key
, to_be
, garbage
, fact
) = args
314 (factoids
, locked
) = get_fact_dbs(who
, where
)
315 if key
.endswith('?'):
318 reply(who
, where
, "I'm sorry, %s, I'm afraid I can't do that." % who
, all
=True)
321 factoids
[key
] = (to_be
, fact
)
322 elif key
in factoids
:
324 do_is
= troggie(do_is
)
325 commands
['do is'] = (Perms
.voice
, do_is
)
327 def forget(who
, where
, args
):
328 (factoids
, locked
) = get_fact_dbs(who
, where
)
331 reply(who
, where
, "I'm sorry, %s, I'm afraid I can't do that." % who
, all
=True)
332 elif key
in factoids
:
334 reply(who
, where
, "I forgot %s." % key
)
336 reply(who
, where
, "I don't have anything matching '%s'." % key
)
337 forget
= troggie(forget
)
338 commands
['forget'] = (Perms
.voice
, forget
)
340 def force(who
, where
, args
):
341 (factoids
, locked
) = get_fact_dbs(who
, where
)
342 if not is_re
.search(args
):
343 reply(who
, where
, "Syntax: $force a (is/are/was/were) b")
345 (key
, to_be
, garbage
, fact
) = resize(is_re
.split(args
, 1),4)
346 if key
.endswith('?'):
349 factoids
[key
] = (to_be
, fact
)
350 elif key
in factoids
:
352 commands
['force'] = (Perms
.op
, force
)
354 def lock(who
, where
, args
):
355 (factoids
, locked
) = get_fact_dbs(who
, where
)
356 if args
.endswith('?'):
358 if not locked
.get(args
):
360 reply(who
, where
, "Done.")
362 reply(who
, where
, "It's already locked.")
363 commands
['lock'] = (Perms
.op
, lock
)
365 def unlock(who
, where
, args
):
366 (factoids
, locked
) = get_fact_dbs(who
, where
)
367 if args
.endswith('?'):
371 reply(who
, where
, "Done.")
373 reply(who
, where
, "It's not locked.")
374 commands
['unlock'] = (Perms
.op
, unlock
)
376 def factoid(who
, where
, args
, implicit
=False):
377 (factoids
, locked
) = get_fact_dbs(who
, where
)
378 if args
.endswith('?'):
381 (to_be
, fact
) = factoids
[args
]
382 if not implicit
and fact
.count("$who"):
386 if lfact
.startswith("<"):
387 if lfact
.startswith("<raw>"):
388 response
= fact
[5:].lstrip()
389 elif lfact
.startswith("<reply>"):
390 response
= fact
[7:].lstrip()
391 elif lfact
.startswith("<action>"):
392 response
= "\x01ACTION %s\x01" % fact
[8:].lstrip()
394 response
= "I hear that %s %s %s" % (args
, to_be
, fact
)
395 response
= response
.replace("$who", who
)
396 reply(who
, where
, response
, all
=implicit
)
398 reply(who
, where
, "I don't have anything matching '%s'." % args
)
399 commands
['fact'] = (Perms
.voice
, factoid
)
400 commands
['factoid'] = (Perms
.voice
, factoid
)
402 def factoid_implicit(who
, where
, args
):
403 factoid(who
, where
, args
, implicit
=True)
404 factoid_implicit
= troggie(factoid_implicit
)
405 commands
['factoid implicit'] = (Perms
.voice
, factoid_implicit
)
407 def get_time(who
, where
, args
):
408 reply(who
, where
, "Current time is: " + get_timestamp())
409 commands
['time'] = (Perms
.voice
, get_time
)
411 def get_reminder_db(who
, where
):
412 return extract_my_db(reminder_dbs
, who
, where
, lambda: [])
414 def describe_reminder(reminder
):
415 (when
, message
, groups
, repeat
) = reminder
416 description
= '"%s" at %s.' % (message
, get_timestamp(when
))
418 groupstr
= ",".join(groups
)
419 description
+= " Groups: " + groupstr
421 hours
= repeat
/ 3600
422 minutes
= str(repeat
/ 60 % 60).zfill(2)
423 description
+= " Repeating every %d:%s." % (hours
, minutes
)
426 reminder_res
= {"add": re
.compile(r
'^"((?:[^"]|\")*)" +at +([^"]*)$',
428 "set": re
.compile(r
'^(\d+) +(\w+) +(.*)$', re
.IGNORECASE
),
429 "repeat h+:mm": re
.compile(r
'^(\d+) +every +(\d+):(\d\d)$',
431 "repeat x units": re
.compile(r
'^(\d+) +every +(\d+) +' +
432 r
'(week|day|hour|minute)s?$',
434 "repeat off": re
.compile(r
'^(\d+) +(off|disable|stop|never|none'
439 time_units
= {"minute": 60,
450 def reminder_index(who
, where
, reminders
, whichstr
):
451 which
= safeint(whichstr
)
453 reply(who
, where
, "Which reminder?")
455 if which
> len(reminders
):
456 reply(who
, where
, "I don't have that many reminders.")
460 def real_where(who
, where
):
465 def fire_reminder(where
, reminders
, reminder
):
466 (when
, message
, groups
, repeat
) = reminder
467 curtime
= time
.time()
468 if when
< (curtime
- 60):
469 delay
= curtime
- when
470 reply('', where
, "Reminder delayed by %d minutes: %s" % (delay
// 60,
474 reply('', where
, message
, all
=True)
477 skip
= delay
// repeat
478 reply('', where
, "(skipping %d delayed repititions)" % skip
, all
=True)
479 real_repeat
= (skip
+ 1) * repeat
482 reminder
[0] += real_repeat
483 schedule_reminder(where
, reminders
, reminder
)
485 reminders
.remove(reminder
)
486 fire_reminder
= safe(fire_reminder
)
488 def schedule_reminder(where
, reminders
, reminder
):
489 scheduler
.enterabs(reminder
[0], 0, fire_reminder
, (where
, reminders
, reminder
))
491 def add_reminder(who
, where
, reminders
, reminder
):
492 if len(reminders
) < 10 or where
== "#casualgameplay":
493 reminders
.append(reminder
)
494 schedule_reminder(real_where(who
, where
), reminders
, reminder
)
495 reply(who
, where
, "Done.")
498 "I'm sorry, %s, I'm afraid I can't do that. You're limited to 10."
501 def cancel_reminder(where
, reminders
, reminder
):
503 scheduler
.cancel((reminder
[0], 0, fire_reminder
, (where
, reminders
, reminder
)))
507 def reschedule(who
, where
, reminders
, reminder
, when
):
508 rwhere
= real_where(who
, where
)
509 cancel_reminder(rwhere
, reminders
, reminder
)
511 schedule_reminder(rwhere
, reminders
, reminder
)
513 def reminder(who
, where
, reminder_args
):
514 (command
, args
) = resize(reminder_args
.split(" ", 1), 2)
515 reminders
= get_reminder_db(who
, where
)
517 reply(who
, where
, "Available reminder commands: add del list set repeat help")
518 elif command
in ("add", "new", "create", "make"):
519 parsed
= reminder_res
["add"].search(args
)
521 reply(who
, where
, "I don't understand that. Try $reminder help add")
523 (msg
, whenstr
) = parsed
.groups()
525 when
= parse_time(whenstr
)
527 reply(who
, where
, "I don't understand that time.")
529 reminder
= [when
, msg
, [], 0]
530 add_reminder(who
, where
, reminders
, reminder
)
531 elif command
in ("del", "delete", "remove", "rm"):
532 which
= reminder_index(who
, where
, reminders
, args
)
535 reminder
= reminders
[which
]
537 cancel_reminder(real_where(who
, where
), reminders
, reminder
)
538 reply(who
, where
, "Deleted reminder %d: %s" %
539 (which
+1, describe_reminder(reminder
)))
540 elif command
in ("list", "show"):
541 if len(reminders
) > 5:
542 reply(who
, where
, "Listing %d reminders in private " % len(reminders
)
543 + "to avoid channel clutter")
546 reply(who
, where
, "No reminders.")
548 for reminder
in reminders
:
549 reply(who
, where
, "%2d. %s" % (index
, describe_reminder(reminder
)))
551 elif command
in ("change", "alter", "set"):
552 parsed
= reminder_res
["set"].search(args
)
554 reply(who
, where
, "I don't understand that. Try $reminder help set")
556 (whichstr
, property, value
) = parsed
.groups()
557 which
= reminder_index(who
, where
, reminders
, whichstr
)
560 reminder
= reminders
[which
]
561 lproperty
= property.lower()
562 if lproperty
in ("message", "msg"):
564 elif lproperty
== "time":
566 when
= parse_time(value
)
567 reschedule(who
, where
, reminders
, reminder
, when
)
569 reply(who
, where
, "I don't understand that time.")
571 elif lproperty
in ("group", "groups"):
572 groups
= value
.split(",")
573 groups
= [group
.strip() for group
in groups
]
575 reply(who
, where
, "Done.")
576 elif command
== "repeat":
577 parse_hm
= reminder_res
["repeat h+:mm"].search(args
)
578 parse_units
= reminder_res
["repeat x units"].search(args
)
579 parse_off
= reminder_res
["repeat off"].search(args
)
580 parsed
= parse_hm
or parse_units
or parse_off
582 which
= reminder_index(who
, where
, reminders
, parsed
.groups()[0])
585 reminder
= reminders
[which
]
587 reply(who
, where
, "I don't understand that. Try $reminder help repeat")
590 (whichstr
, hourstr
, minutestr
) = parsed
.groups()
591 hours
= safeint(hourstr
)
593 reply(who
, where
, "Bad number of hours.")
595 minutes
= safeint(minutestr
)
596 # Mathematicians, read at your own peril.
598 reply(who
, where
, "Bad number of minutes.")
600 if hours
== minutes
== 0:
601 reply(who
, where
, "Repeating continuously sounds like a bad idea.")
603 reminder
[3] = 60 * (minutes
+ 60 * hours
)
605 "Reminder number %d now repeating every %d hours and %d minutes."
606 % (which
+1, hours
, minutes
))
608 (whichstr
, numstr
, unit
) = parsed
.groups()
610 num
= safeint(numstr
)
612 reply(who
, where
, "Bad number of %ss." % unit
)
614 if unit
not in time_units
:
615 reply(who
, where
, "I don't know that unit.")
617 reminder
[3] = num
* time_units
[unit
]
618 reply(who
, where
, "Reminder number %d now repeating every %d %ss."
619 % (which
+1, num
, unit
))
622 reply(who
, where
, "Repeating disabled on reminder %d." % which
+1)
624 elif command
== "help":
626 reply(who
, where
, "To get help on a specific command, type $reminder " \
627 + "help <command> (e.g. $reminder help add). " \
628 + "Available reminder commands: add del list set "\
630 elif args
in ("add", "new", "create", "make"):
631 reply(who
, where
, '$reminder add "<msg>" at <time>: Adds a new ' \
632 + "reminder. When <time> comes, I will say <msg>. A" \
633 + " variety of time formats are supported. Use $time" \
634 + " to get my current time for comparison.")
635 elif args
in ("del", "delete", "remove", "rm"):
636 reply(who
, where
, "$reminder del <reminder>: Delete reminder number " \
638 elif args
in ("change", "alter", "set"):
639 reply(who
, where
, "$reminder set <reminder> <property> <value>: Change" \
640 + " <property> of reminder number <reminder> to " \
641 + "<value>. Availale properties: message, time, group")
642 elif args
in ("list", "show"):
643 reply(who
, where
, "$reminder list: Print a list of reminders. If there" \
644 + " are more than 5, I will reply in private.")
645 elif args
== "repeat":
646 reply(who
, where
, "$reminder repeat <reminder> every <interval>: " \
647 + "Reminder number <reminder> will be repeated every " \
648 + "<interval>. Use $reminder repeat <reminder> off to"\
649 + " stop repeating a reminder.")
651 reply(who
, where
, "$reminder help <command>: get help on <command>. " \
652 + "You know, like you just did.")
654 reply(who
, where
, "I don't understand that.")
655 commands
['reminder'] = (Perms
.admin
, reminder
)
656 commands
['reminders'] = (Perms
.admin
, reminder
)
658 def subscribe(who
, where
, args
):
660 reply(who
, where
, "Don't you think subscribing to reminders that are" +
661 " already in PM is a bit... pointless?")
665 def do_commands(who
):
666 user
= whois_info
[who
]
667 for where
, command
, args
in waiting_commands
[who
]:
668 if command
not in commands
:
669 command
= 'raise error'
670 args
= "I don't understand that."
671 (required_perms
, do_it
) = commands
[command
]
672 if required_perms
<= get_perms(who
, where
):
673 safe_call(do_it
, (who
, where
, args
))
674 waiting_commands
[who
] = []
677 def got_whois(conn
, event
):
678 user
= event
.arguments()[0]
679 whois_info
[user
] = Whois()
680 got_whois
= safe(got_whois
)
681 irc
.add_global_handler("whoisuser", got_whois
)
682 irc
.add_global_handler("nosuchnick", got_whois
)
685 def got_registered(conn
, event
):
686 args
= event
.arguments()
687 if len(args
) == 2 and args
[1] == "is a registered nick":
689 whois_info
[user
].registered
= True
690 got_registered
= safe(got_registered
)
691 irc
.add_global_handler("307", got_registered
)
694 def got_channels(conn
, event
):
695 args
= event
.arguments()
698 channels
= args
[1].split()
701 whois_info
[user
].channel_perms
[c
[1:]] = Perms
.from_symbol(c
[0])
703 whois_info
[user
].channel_perms
[c
] = Perms
.present
704 got_channels
= safe(got_channels
)
705 irc
.add_global_handler("whoischannels", got_channels
)
708 def got_servop(conn
, event
):
709 args
= event
.arguments()
712 whois_info
[user
].ircop
= True
713 got_servop
= safe(got_servop
)
714 irc
.add_global_handler("whoisoperator", got_servop
)
717 def got_whoend(conn
, event
):
718 who
= event
.arguments()[0]
721 user
= whois_info
[who
]
722 print "Who info for %s:" % who
723 print "Registered: %s" % user
.registered
724 print "IRCop: %s" % user
.ircop
725 p
= user
.channel_perms
726 perms
= "".join([("%s: %s, " % (k
, p
[k
])) for k
in p
])[:-2]
727 print "Channel info: %s" % perms
728 got_whoend
= safe(got_whoend
)
729 irc
.add_global_handler("endofwhois", got_whoend
)
732 def got_invite(conn
, event
):
733 who
= irclib
.nm_to_n(event
.source())
734 where
= event
.arguments()[0]
735 got_command(who
, where
, "do join")
736 got_invite
= safe(got_invite
)
737 irc
.add_global_handler("invite", got_invite
)
740 def got_msg(conn
, event
):
741 for user
in my_users
:
742 if irclib
.mask_matches(event
.source(), user
):
743 if my_users
[user
] == Perms
.ban
:
745 msg
= event
.arguments()[0]
746 who
= irclib
.nm_to_n(event
.source())
747 (command
, args
) = resize(msg
.split(" ", 1),2)
748 if command
and command
[0] == "$":
749 command
= command
[1:]
751 if event
.eventtype() == 'privmsg':
754 where
= event
.target()
755 if msg
.count("http://"):
756 got_command(who
, where
, "title implicit", html
.extract_url(msg
))
758 if nick_re
.match(msg
):
759 (me
, command
, args
) = resize(msg
.split(" ", 2),3)
760 if command
in commands
:
762 elif is_re
.search(msg
):
764 args
= is_re
.split(msg
.split(" ", 1)[1], 1)
766 command
= "factoid implicit"
767 args
= msg
.split(" ", 1)[1]
769 if command
in commands
and commands
[command
][0] <= Perms
.voice
:
771 elif is_re
.search(msg
):
773 args
= is_re
.split(msg
, 1)
775 command
= "factoid implicit"
777 got_command(who
, where
, command
, args
)
778 got_msg
= safe(got_msg
)
779 irc
.add_global_handler("privmsg", got_msg
)
780 irc
.add_global_handler("pubmsg", got_msg
)
785 cmd
= sys
.stdin
.readline().strip()
787 hal
.connection
.send_raw(cmd
)
788 thread
.start_new_thread(debug_console
, ())
791 for where
in reminder_dbs
.keys():
792 db
= reminder_dbs
[where
]
794 schedule_reminder(where
, db
, reminder
)
795 while True: # Looping in case of errors.
796 safe(scheduler
.run_forever
)()
797 thread
.start_new_thread(run_reminders
, ())
799 hal
.ircobj
.process_forever(None)