Move our various bots into api/bots/.
(imported from commit f5803441b9b84872b942dff8e1c0ad1100788bcd)
This commit is contained in:
parent
221cfc7717
commit
1cb32fad7f
6 changed files with 0 additions and 0 deletions
0
bots/__init__.py
Normal file
0
bots/__init__.py
Normal file
155
bots/check-mirroring
Executable file
155
bots/check-mirroring
Executable file
|
@ -0,0 +1,155 @@
|
|||
#!/usr/bin/python
|
||||
import urllib
|
||||
import sys
|
||||
import logging
|
||||
import traceback
|
||||
import simplejson
|
||||
import re
|
||||
import time
|
||||
import subprocess
|
||||
import optparse
|
||||
import os
|
||||
import datetime
|
||||
import textwrap
|
||||
import signal
|
||||
import random
|
||||
from urllib2 import HTTPError
|
||||
|
||||
root_path = "/mit/tabbott/for_friends"
|
||||
sys.path.append(root_path + "/python-zephyr")
|
||||
sys.path.append(root_path + "/python-zephyr/build/lib.linux-x86_64-2.6/")
|
||||
|
||||
parser = optparse.OptionParser()
|
||||
parser.add_option('--verbose',
|
||||
dest='verbose',
|
||||
default=False,
|
||||
action='store_true')
|
||||
parser.add_option('--site',
|
||||
dest='site',
|
||||
default="https://app.humbughq.com",
|
||||
action='store')
|
||||
(options, args) = parser.parse_args()
|
||||
|
||||
mit_user = 'tabbott/extra@ATHENA.MIT.EDU'
|
||||
humbug_user = 'tabbott/extra@mit.edu'
|
||||
|
||||
zhkey1 = random.getrandbits(32)
|
||||
hzkey1 = random.getrandbits(32)
|
||||
zhkey2 = random.getrandbits(32)
|
||||
hzkey2 = random.getrandbits(32)
|
||||
|
||||
sys.path.append(".")
|
||||
sys.path.append(os.path.dirname(os.path.dirname(__file__)))
|
||||
import api.common
|
||||
humbug_client = api.common.HumbugAPI(email=humbug_user,
|
||||
api_key="xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
|
||||
verbose=True,
|
||||
client="test: Humbug API",
|
||||
site=options.site)
|
||||
|
||||
def print_zephyr(notice):
|
||||
print notice.cls, notice.instance, notice.sender, notice.message.split('\0')[1]
|
||||
|
||||
def print_humbug(message):
|
||||
if message['type'] == "stream":
|
||||
print message["type"], message['display_recipient'], message['subject'], \
|
||||
message['sender_email'], message['content']
|
||||
else:
|
||||
print message["type"], message['sender_email'], \
|
||||
message['display_recipient'], message['content']
|
||||
|
||||
child_pid = os.fork()
|
||||
if child_pid == 0:
|
||||
# Run the humbug => zephyr mirror in the child
|
||||
time.sleep(3)
|
||||
humbug_client.send_message({
|
||||
"type": "personal",
|
||||
"content": str(hzkey1),
|
||||
"recipient": humbug_user,
|
||||
});
|
||||
time.sleep(0.2)
|
||||
humbug_client.send_message({
|
||||
"type": "stream",
|
||||
"subject": "test",
|
||||
"content": str(hzkey2),
|
||||
"stream": "tabbott-nagios-test",
|
||||
});
|
||||
print "Sent Humbug messages!"
|
||||
time.sleep(0.5)
|
||||
|
||||
import zephyr
|
||||
zephyr.init()
|
||||
zsig = "Timothy Good Abbott"
|
||||
|
||||
zeph = zephyr.ZNotice(sender=mit_user, auth=True, recipient=mit_user,
|
||||
cls="message", instance="personal")
|
||||
zeph.setmessage("%s\0%s" % (zsig, zhkey1))
|
||||
zeph.send()
|
||||
time.sleep(0.2)
|
||||
|
||||
zeph = zephyr.ZNotice(sender=mit_user, auth=True,
|
||||
cls="tabbott-nagios-test", instance="test")
|
||||
zeph.setmessage("%s\0%s" % (zsig, zhkey2))
|
||||
zeph.send()
|
||||
print "Sent Zephyr messages!"
|
||||
|
||||
|
||||
else:
|
||||
failed = False
|
||||
import zephyr
|
||||
zephyr.init()
|
||||
subs = zephyr.Subscriptions()
|
||||
subs.add(('message', 'personal', 'tabbott/extra@ATHENA.MIT.EDU'))
|
||||
subs.add(('tabbott-nagios-test', '*', '*'))
|
||||
|
||||
res = humbug_client.get_messages({'server_generation': '0',
|
||||
'first': '0',
|
||||
'last': '1000000000000',})
|
||||
max_message_id = res['max_message_id']
|
||||
|
||||
time.sleep(10)
|
||||
print "Receiving messages!"
|
||||
notices = []
|
||||
while True:
|
||||
notice = zephyr.receive(block=False)
|
||||
if notice is None:
|
||||
break
|
||||
if notice.opcode != "":
|
||||
continue
|
||||
notices.append(notice)
|
||||
if len(notices) != 4:
|
||||
print "humbug=>zephyr: Got wrong number of messages back!"
|
||||
failed = True
|
||||
elif (notices[0].message.split('\0')[1] != str(hzkey1) or
|
||||
notices[1].message.split('\0')[1] != str(hzkey2) or
|
||||
notices[2].message.split('\0')[1] != str(zhkey1) or
|
||||
notices[3].message.split('\0')[1] != str(zhkey2)):
|
||||
print "humbug=>zephyr: Didn't get back right values!"
|
||||
failed = True
|
||||
if failed:
|
||||
for notice in notices:
|
||||
print_zephyr(notice)
|
||||
|
||||
messages = humbug_client.get_messages({'first': '0',
|
||||
'last': str(max_message_id),
|
||||
'server_generation': '0'})['messages']
|
||||
if len(messages) != 4:
|
||||
print "zephyr=>humbug: Didn't get exactly 4 messages!"
|
||||
for message in messages:
|
||||
print_humbug(message)
|
||||
failed = True
|
||||
elif (messages[0]['content'] != str(hzkey1) or
|
||||
messages[1]['content'] != str(hzkey2) or
|
||||
messages[2]['content'] != str(zhkey1) or
|
||||
messages[3]['content'] != str(zhkey2)):
|
||||
print "zephyr=>humbug: Didn't get back right values!"
|
||||
for message in messages:
|
||||
print_humbug(message)
|
||||
failed = True
|
||||
|
||||
if failed:
|
||||
print "original keys:", zhkey1, zhkey2, hzkey1, hzkey2
|
||||
sys.exit(1)
|
||||
|
||||
print "Success!"
|
||||
sys.exit(0)
|
147
bots/gcal-bot
Executable file
147
bots/gcal-bot
Executable file
|
@ -0,0 +1,147 @@
|
|||
#!/usr/bin/env python
|
||||
import sys
|
||||
import time
|
||||
import datetime
|
||||
import optparse
|
||||
import urlparse
|
||||
import itertools
|
||||
import traceback
|
||||
from os import path
|
||||
|
||||
sys.path.append(path.join(path.dirname(__file__), '..'))
|
||||
import api.common
|
||||
|
||||
parser = optparse.OptionParser(r"""
|
||||
|
||||
%prog \
|
||||
--user foo@humbughq.com \
|
||||
--api-key 0123456789abcdef0123456789abcdef \
|
||||
--calendar http://www.google.com/calendar/feeds/foo%40humbughq.com/private-fedcba9876543210fedcba9876543210/basic
|
||||
|
||||
Send yourself reminders on Humbug of Google Calendar events.
|
||||
|
||||
To get the calendar URL:
|
||||
- Load Google Calendar in a web browser
|
||||
- Find your calendar in the "My calendars" list on the left
|
||||
- Click the down-wedge icon that appears on mouseover, and select "Calendar settings"
|
||||
- Copy the link address for the "XML" button under "Private Address"
|
||||
|
||||
Run this on your personal machine. Your API key and calendar URL are revealed to local
|
||||
users through the command line.
|
||||
|
||||
Depends on: python-gdata
|
||||
""")
|
||||
|
||||
parser.add_option('--user',
|
||||
dest='user',
|
||||
action='store',
|
||||
help='Humbug user email address',
|
||||
metavar='EMAIL')
|
||||
parser.add_option('--api-key',
|
||||
dest='api_key',
|
||||
action='store',
|
||||
help='API key for that user')
|
||||
parser.add_option('--calendar',
|
||||
dest='calendar',
|
||||
action='store',
|
||||
help='Google Calendar XML "Private Address"',
|
||||
metavar='URL')
|
||||
parser.add_option('--site',
|
||||
dest='site',
|
||||
default="https://app.humbughq.com",
|
||||
action='store',
|
||||
help='Humbug site [default: https://app.humbughq.com]',
|
||||
metavar='URL')
|
||||
parser.add_option('--interval',
|
||||
dest='interval',
|
||||
default=10,
|
||||
type=int,
|
||||
action='store',
|
||||
help='Minutes before event for reminder [default: 10]',
|
||||
metavar='MINUTES')
|
||||
|
||||
(options, args) = parser.parse_args()
|
||||
|
||||
if not (options.user and options.api_key and options.calendar):
|
||||
parser.error('You must specify --user, --api-key, and --calendar')
|
||||
|
||||
try:
|
||||
from gdata.calendar.client import CalendarClient
|
||||
except ImportError:
|
||||
parser.error('Install python-gdata')
|
||||
|
||||
def get_calendar_url():
|
||||
parts = urlparse.urlparse(options.calendar)
|
||||
pat = path.split(parts.path)
|
||||
if pat[1] != 'basic':
|
||||
parser.error('The --calendar URL should be the XML "Private Address" ' +
|
||||
'from your calendar settings')
|
||||
return urlparse.urlunparse((parts.scheme, parts.netloc, pat[0] + '/full',
|
||||
'', 'futureevents=true&orderby=startdate', ''))
|
||||
|
||||
calendar_url = get_calendar_url()
|
||||
|
||||
humbug = api.common.HumbugAPI(email=options.user,
|
||||
api_key=options.api_key,
|
||||
site=options.site,
|
||||
verbose=True)
|
||||
|
||||
def get_events():
|
||||
feed = CalendarClient().GetCalendarEventFeed(uri=calendar_url)
|
||||
|
||||
for event in feed.entry:
|
||||
start = event.when[0].start.split('.')[0]
|
||||
start = datetime.datetime.strptime(start, '%Y-%m-%dT%H:%M:%S')
|
||||
yield (event.uid.value, start, event.title.text)
|
||||
|
||||
# Our cached view of the calendar, updated periodically.
|
||||
events = []
|
||||
|
||||
# Unique keys for events we've already sent, so we don't remind twice.
|
||||
sent = set()
|
||||
|
||||
def send_reminders():
|
||||
global sent
|
||||
|
||||
messages = []
|
||||
keys = set()
|
||||
now = datetime.datetime.now()
|
||||
|
||||
for uid, start, title in events:
|
||||
dt = start - now
|
||||
if dt.days == 0 and dt.seconds < 60*options.interval:
|
||||
# The unique key includes the start time, because of
|
||||
# repeating events.
|
||||
key = (uid, start)
|
||||
if key not in sent:
|
||||
line = '%s starts at %s' % (title, start.strftime('%H:%M'))
|
||||
print 'Sending reminder:', line
|
||||
messages.append(line)
|
||||
keys.add(key)
|
||||
|
||||
if not messages:
|
||||
return
|
||||
|
||||
if len(messages) == 1:
|
||||
message = 'Reminder: ' + messages[0]
|
||||
else:
|
||||
message = 'Reminder:\n\n' + '\n'.join('* ' + m for m in messages)
|
||||
|
||||
humbug.send_message(dict(
|
||||
type = 'personal',
|
||||
recipient = options.user,
|
||||
content = message))
|
||||
|
||||
sent |= keys
|
||||
|
||||
# Loop forever
|
||||
for i in itertools.count():
|
||||
try:
|
||||
# We check reminders every minute, but only
|
||||
# download the calendar every 10 minutes.
|
||||
if not i % 10:
|
||||
events = list(get_events())
|
||||
send_reminders()
|
||||
except:
|
||||
traceback.print_exc()
|
||||
time.sleep(60)
|
82
bots/humbug_trac.py
Normal file
82
bots/humbug_trac.py
Normal file
|
@ -0,0 +1,82 @@
|
|||
#!/usr/bin/python
|
||||
#
|
||||
# Humbug trac plugin -- sends humbugs when tickets change.
|
||||
#
|
||||
# Install by placing in the plugins/ subdirectory and then adding
|
||||
# "humbug_trac" to the [components] section of the conf/trac.ini file,
|
||||
# like so:
|
||||
#
|
||||
# [components]
|
||||
# humbug_trac = enabled
|
||||
#
|
||||
# You may then need to restart trac (or restart Apache) for the bot
|
||||
# (or changes to the bot) to actually be loaded by trac.
|
||||
#
|
||||
# Our install is trac.humbughq.com:/home/humbug/trac/
|
||||
|
||||
from trac.core import Component, implements
|
||||
from trac.ticket import ITicketChangeListener
|
||||
import sys
|
||||
|
||||
sys.path.append("/home/humbug/humbug")
|
||||
import api.common
|
||||
client = api.common.HumbugAPI(email="humbug+trac@humbughq.com",
|
||||
api_key="xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx")
|
||||
|
||||
def markdown_ticket_url(ticket, heading="ticket"):
|
||||
return "[%s #%s](https://trac.humbughq.com/ticket/%s)" % (heading, ticket.id, ticket.id)
|
||||
|
||||
def markdown_block(desc):
|
||||
return "\n\n>" + "\n> ".join(desc.split("\n")) + "\n"
|
||||
|
||||
def trac_subject(ticket):
|
||||
return "Trac #%s" % ticket.id
|
||||
|
||||
def send_update(ticket, content):
|
||||
client.send_message({
|
||||
"type": "stream",
|
||||
"stream": "devel",
|
||||
"content": content,
|
||||
"subject": trac_subject(ticket)
|
||||
})
|
||||
|
||||
class HumbugPlugin(Component):
|
||||
implements(ITicketChangeListener)
|
||||
|
||||
def ticket_created(self, ticket):
|
||||
"""Called when a ticket is created."""
|
||||
content = "%s created new %s in component %s:\n%s" % (ticket.values.get("reporter"),
|
||||
markdown_ticket_url(ticket),
|
||||
ticket.values.get("component"),
|
||||
ticket.values.get("summary"))
|
||||
if ticket.values.get("description") != "":
|
||||
content += ":%s" % markdown_block(ticket.values.get("description"))
|
||||
send_update(ticket, content)
|
||||
|
||||
def ticket_changed(self, ticket, comment, author, old_values):
|
||||
"""Called when a ticket is modified.
|
||||
|
||||
`old_values` is a dictionary containing the previous values of the
|
||||
fields that have changed.
|
||||
"""
|
||||
content = "%s updated %s:\n\n" % (author, markdown_ticket_url(ticket))
|
||||
for key in old_values.keys():
|
||||
if key == "description":
|
||||
content += '- Changed %s from %s to %s' % (key, markdown_block(old_values.get(key)),
|
||||
markdown_block(ticket.values.get(key)))
|
||||
elif old_values.get(key) == "":
|
||||
content += '- Added %s **%s**\n' % (key, ticket.values.get(key))
|
||||
elif ticket.values.get(key) == "":
|
||||
content += '- Remove %s **%s**\n' % (key, old_values.get(key))
|
||||
else:
|
||||
content += '- Changed %s from **%s** to **%s**\n' % (key, old_values.get(key),
|
||||
ticket.values.get(key))
|
||||
|
||||
if comment:
|
||||
content += '- Added a comment: %s' % (markdown_block(comment,))
|
||||
send_update(ticket, content)
|
||||
|
||||
def ticket_deleted(self, ticket):
|
||||
"""Called when a ticket is deleted."""
|
||||
content = "%s was deleted." % markdown_ticket_url(ticket, heading="Ticket")
|
||||
send_update(ticket, content)
|
8
bots/mit_subs_list.py
Normal file
8
bots/mit_subs_list.py
Normal file
|
@ -0,0 +1,8 @@
|
|||
subs_lists = {}
|
||||
subs_lists['default'] = """\
|
||||
""".split()
|
||||
|
||||
all_subs = set()
|
||||
for sub_list in subs_lists.values():
|
||||
for sub in sub_list:
|
||||
all_subs.add(sub)
|
457
bots/zephyr_mirror.py
Executable file
457
bots/zephyr_mirror.py
Executable file
|
@ -0,0 +1,457 @@
|
|||
#!/usr/bin/python
|
||||
import urllib
|
||||
import sys
|
||||
import logging
|
||||
import traceback
|
||||
import simplejson
|
||||
import re
|
||||
import time
|
||||
import subprocess
|
||||
import optparse
|
||||
import os
|
||||
import datetime
|
||||
import textwrap
|
||||
import signal
|
||||
from urllib2 import HTTPError
|
||||
|
||||
root_path = "/mit/tabbott/for_friends"
|
||||
sys.path.append(root_path + "/python-zephyr")
|
||||
sys.path.append(root_path + "/python-zephyr/build/lib.linux-x86_64-2.6/")
|
||||
|
||||
parser = optparse.OptionParser()
|
||||
parser.add_option('--forward-class-messages',
|
||||
dest='forward_class_messages',
|
||||
default=False,
|
||||
action='store_true')
|
||||
parser.add_option('--resend-log',
|
||||
dest='resend_log',
|
||||
default=False,
|
||||
action='store_true')
|
||||
parser.add_option('--enable-log',
|
||||
dest='enable_log',
|
||||
default=False,
|
||||
action='store_true')
|
||||
parser.add_option('--no-forward-personals',
|
||||
dest='forward_personals',
|
||||
default=True,
|
||||
action='store_false')
|
||||
parser.add_option('--forward-from-humbug',
|
||||
dest='forward_from_humbug',
|
||||
default=False,
|
||||
action='store_true')
|
||||
parser.add_option('--verbose',
|
||||
dest='verbose',
|
||||
default=False,
|
||||
action='store_true')
|
||||
parser.add_option('--no-auto-subscribe',
|
||||
dest='auto_subscribe',
|
||||
default=True,
|
||||
action='store_false')
|
||||
parser.add_option('--site',
|
||||
dest='site',
|
||||
default="https://app.humbughq.com",
|
||||
action='store')
|
||||
parser.add_option('--user',
|
||||
dest='user',
|
||||
default=os.environ["USER"],
|
||||
action='store')
|
||||
parser.add_option('--api-key-file',
|
||||
dest='api_key_file',
|
||||
default=os.path.join(os.environ["HOME"], "Private", ".humbug-api-key"),
|
||||
action='store')
|
||||
(options, args) = parser.parse_args()
|
||||
|
||||
api_key = file(options.api_key_file).read().strip()
|
||||
|
||||
sys.path.append(".")
|
||||
sys.path.append(os.path.dirname(os.path.dirname(__file__)))
|
||||
import api.common
|
||||
humbug_client = api.common.HumbugAPI(email=options.user + "@mit.edu",
|
||||
api_key=api_key,
|
||||
verbose=True,
|
||||
client="zephyr_mirror",
|
||||
site=options.site)
|
||||
|
||||
start_time = time.time()
|
||||
|
||||
def humbug_username(zephyr_username):
|
||||
return zephyr_username.lower().split("@")[0] + "@mit.edu"
|
||||
|
||||
def unwrap_lines(body):
|
||||
# Split into paragraphs at two consecutive newlines, or a newline followed
|
||||
# by an indent.
|
||||
return '\n\n'.join(p.replace('\n', ' ') for p in re.split(r'\n[ \t\n]', body))
|
||||
|
||||
def send_humbug(zeph):
|
||||
if options.forward_class_messages:
|
||||
zeph["forged"] = "yes"
|
||||
zeph["sender"] = humbug_username(zeph["sender"])
|
||||
zeph['fullname'] = username_to_fullname(zeph['sender'])
|
||||
zeph['shortname'] = zeph['sender'].split('@')[0]
|
||||
if "subject" in zeph:
|
||||
zeph["subject"] = zeph["subject"][:60]
|
||||
if zeph['type'] == 'stream':
|
||||
# Forward messages sent to -c foo -i bar to stream bar subject "instance"
|
||||
if zeph["stream"] == "message":
|
||||
zeph['stream'] = zeph['subject']
|
||||
zeph['subject'] = "instance %s" % (zeph['stream'])
|
||||
elif zeph["stream"] == "tabbott-test5":
|
||||
zeph['stream'] = zeph['subject']
|
||||
zeph['subject'] = "test instance %s" % (zeph['stream'])
|
||||
|
||||
for key in zeph.keys():
|
||||
if isinstance(zeph[key], unicode):
|
||||
zeph[key] = zeph[key].encode("utf-8")
|
||||
elif isinstance(zeph[key], str):
|
||||
zeph[key] = zeph[key].decode("utf-8")
|
||||
|
||||
zeph['content'] = unwrap_lines(zeph['content'])
|
||||
return humbug_client.send_message(zeph)
|
||||
|
||||
def fetch_fullname(username):
|
||||
try:
|
||||
match_user = re.match(r'([a-zA-Z0-9_]+)@mit\.edu', username)
|
||||
if match_user:
|
||||
proc = subprocess.Popen(['hesinfo', match_user.group(1), 'passwd'],
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.PIPE)
|
||||
out, _err_unused = proc.communicate()
|
||||
if proc.returncode == 0:
|
||||
return out.split(':')[4].split(',')[0]
|
||||
except:
|
||||
print >>sys.stderr, '%s: zephyr=>humbug: Error getting fullname for %s' % \
|
||||
(datetime.datetime.now(), username)
|
||||
traceback.print_exc()
|
||||
|
||||
domains = [
|
||||
("@CS.CMU.EDU", " (CMU)"),
|
||||
("@ANDREW.CMU.EDU", " (CMU)"),
|
||||
("@IASTATE.EDU", " (IASTATE)"),
|
||||
("@1TS.ORG", " (1TS)"),
|
||||
("@DEMENTIA.ORG", " (DEMENTIA)"),
|
||||
("@MIT.EDU", ""),
|
||||
]
|
||||
for (domain, tag) in domains:
|
||||
if username.upper().endswith(domain):
|
||||
return username.split("@")[0] + tag
|
||||
return username
|
||||
|
||||
fullnames = {}
|
||||
def username_to_fullname(username):
|
||||
if username not in fullnames:
|
||||
fullnames[username] = fetch_fullname(username)
|
||||
return fullnames[username]
|
||||
|
||||
current_zephyr_subs = {}
|
||||
def ensure_subscribed(sub):
|
||||
if sub in current_zephyr_subs:
|
||||
return
|
||||
subs.add((sub, '*', '*'))
|
||||
current_zephyr_subs[sub] = True
|
||||
|
||||
def update_subscriptions_from_humbug():
|
||||
try:
|
||||
res = humbug_client.get_public_streams()
|
||||
streams = res["streams"]
|
||||
except:
|
||||
print "%s: Error getting public streams:" % (datetime.datetime.now())
|
||||
traceback.print_exc()
|
||||
return
|
||||
for stream in streams:
|
||||
ensure_subscribed(stream)
|
||||
|
||||
def maybe_restart_mirroring_script():
|
||||
if os.stat(root_path + "/restart_stamp").st_mtime > start_time or \
|
||||
(options.user == "tabbott" and
|
||||
os.stat(root_path + "/tabbott_stamp").st_mtime > start_time):
|
||||
print
|
||||
print "%s: zephyr mirroring script has been updated; restarting..." % \
|
||||
(datetime.datetime.now())
|
||||
os.kill(child_pid, signal.SIGKILL)
|
||||
while True:
|
||||
try:
|
||||
os.execvp(root_path + "/zephyr_mirror.py", sys.argv)
|
||||
except:
|
||||
print "Error restarting, trying again."
|
||||
traceback.print_exc()
|
||||
time.sleep(10)
|
||||
|
||||
def process_loop(log):
|
||||
sleep_count = 0
|
||||
sleep_time = 0.1
|
||||
while True:
|
||||
notice = zephyr.receive(block=False)
|
||||
if notice is not None:
|
||||
try:
|
||||
process_notice(notice, log)
|
||||
except:
|
||||
print >>sys.stderr, '%s: zephyr=>humbug: Error relaying zephyr' % \
|
||||
(datetime.datetime.now())
|
||||
traceback.print_exc()
|
||||
time.sleep(2)
|
||||
|
||||
maybe_restart_mirroring_script()
|
||||
|
||||
time.sleep(sleep_time)
|
||||
sleep_count += sleep_time
|
||||
if sleep_count > 15:
|
||||
sleep_count = 0
|
||||
if options.forward_class_messages:
|
||||
# Ask the Humbug server about any new classes to subscribe to
|
||||
update_subscriptions_from_humbug()
|
||||
continue
|
||||
|
||||
def process_notice(notice, log):
|
||||
try:
|
||||
zsig, body = notice.message.split("\x00", 1)
|
||||
except ValueError:
|
||||
body = notice.message
|
||||
zsig = ""
|
||||
is_personal = False
|
||||
is_huddle = False
|
||||
|
||||
if notice.opcode == "PING":
|
||||
# skip PING messages
|
||||
return
|
||||
|
||||
if isinstance(zsig, str):
|
||||
# Check for width unicode character u'\u200B'.encode("utf-8")
|
||||
if u'\u200B'.encode("utf-8") in zsig:
|
||||
print "%s: zephyr=>humbug: Skipping message from Humbug!" % \
|
||||
(datetime.datetime.now())
|
||||
return
|
||||
|
||||
sender = notice.sender.lower().replace("athena.mit.edu", "mit.edu")
|
||||
recipient = notice.recipient.lower().replace("athena.mit.edu", "mit.edu")
|
||||
zephyr_class = notice.cls.lower()
|
||||
instance = notice.instance.lower()
|
||||
|
||||
if (zephyr_class == "message" and recipient != ""):
|
||||
is_personal = True
|
||||
if body.startswith("CC:"):
|
||||
is_huddle = True
|
||||
# Map "CC: sipbtest espuser" => "starnine@mit.edu,espuser@mit.edu"
|
||||
huddle_recipients_list = [humbug_username(x.strip()) for x in
|
||||
body.split("\n")[0][4:].split()]
|
||||
if sender not in huddle_recipients_list:
|
||||
huddle_recipients_list.append(sender)
|
||||
huddle_recipients = ",".join(huddle_recipients_list)
|
||||
if (zephyr_class == "mail" and instance == "inbox"):
|
||||
is_personal = True
|
||||
|
||||
# Drop messages not to the listed subscriptions
|
||||
if (zephyr_class not in current_zephyr_subs) and not \
|
||||
(is_personal and options.forward_personals):
|
||||
print "%s: zephyr=>humbug: Skipping ... %s/%s/%s" % \
|
||||
(datetime.datetime.now(), zephyr_class, instance, is_personal)
|
||||
return
|
||||
|
||||
if is_huddle:
|
||||
zeph = { 'type' : 'personal',
|
||||
'time' : str(notice.time),
|
||||
'sender' : sender,
|
||||
'recipient' : huddle_recipients,
|
||||
'zsig' : zsig, # logged here but not used by app
|
||||
'content' : body.split("\n", 1)[1] }
|
||||
elif is_personal:
|
||||
zeph = { 'type' : 'personal',
|
||||
'time' : str(notice.time),
|
||||
'sender' : sender,
|
||||
'recipient' : humbug_username(recipient),
|
||||
'zsig' : zsig, # logged here but not used by app
|
||||
'content' : body }
|
||||
else:
|
||||
zeph = { 'type' : 'stream',
|
||||
'time' : str(notice.time),
|
||||
'sender' : sender,
|
||||
'stream' : zephyr_class,
|
||||
'subject' : instance,
|
||||
'zsig' : zsig, # logged here but not used by app
|
||||
'content' : body }
|
||||
|
||||
# Add instances in for instanced personals
|
||||
if zeph['type'] == "personal" and instance != "personal":
|
||||
zeph["content"] = "[-i %s]" % (instance,) + "\n" + zeph["content"]
|
||||
|
||||
print "%s: zephyr=>humbug: received a message on %s/%s from %s..." % \
|
||||
(datetime.datetime.now(), zephyr_class, instance, notice.sender)
|
||||
log.write(simplejson.dumps(zeph) + '\n')
|
||||
log.flush()
|
||||
|
||||
res = send_humbug(zeph)
|
||||
if res.get("result") != "success":
|
||||
print >>sys.stderr, 'Error relaying zephyr'
|
||||
print zeph
|
||||
print res
|
||||
|
||||
|
||||
def zephyr_to_humbug(options):
|
||||
import mit_subs_list
|
||||
if options.auto_subscribe:
|
||||
add_humbug_subscriptions()
|
||||
if options.forward_class_messages:
|
||||
for sub in mit_subs_list.all_subs:
|
||||
ensure_subscribed(sub)
|
||||
update_subscriptions_from_humbug()
|
||||
if options.forward_personals:
|
||||
subs.add(("message", "*", options.user + "@ATHENA.MIT.EDU"))
|
||||
if subscribed_to_mail_messages():
|
||||
subs.add(("mail", "inbox", options.user + "@ATHENA.MIT.EDU"))
|
||||
|
||||
if options.resend_log:
|
||||
with open('zephyrs', 'r') as log:
|
||||
for ln in log:
|
||||
try:
|
||||
zeph = simplejson.loads(ln)
|
||||
print "%s: zephyr=>humbug: sending saved message to %s from %s..." % \
|
||||
(datetime.datetime.now(), zeph.get('class', zeph.get('recipient')),
|
||||
zeph['sender'])
|
||||
send_humbug(zeph)
|
||||
except:
|
||||
print >>sys.stderr, 'Could not send saved zephyr'
|
||||
traceback.print_exc()
|
||||
time.sleep(2)
|
||||
|
||||
print "%s: zephyr=>humbug: Starting receive loop." % (datetime.datetime.now(),)
|
||||
|
||||
if options.enable_log:
|
||||
log_file = "zephyrs"
|
||||
else:
|
||||
log_file = "/dev/null"
|
||||
|
||||
with open(log_file, 'a') as log:
|
||||
process_loop(log)
|
||||
|
||||
def forward_to_zephyr(message):
|
||||
zsig = u"%s\u200B" % (username_to_fullname(message["sender_email"]))
|
||||
if ' dot ' in zsig:
|
||||
print "%s: humbug=>zephyr: ERROR! Couldn't compute zsig for %s!" % \
|
||||
(datetime.datetime.now(), message["sender_email"])
|
||||
return
|
||||
|
||||
wrapped_content = "\n".join("\n".join(textwrap.wrap(line))
|
||||
for line in message["content"].split("\n"))
|
||||
|
||||
sender_email = message["sender_email"].replace("mit.edu", "ATHENA.MIT.EDU")
|
||||
print "%s: humbug=>zephyr: Forwarding message from %s" % \
|
||||
(datetime.datetime.now(), sender_email)
|
||||
if message['type'] == "stream":
|
||||
zephyr_class = message["display_recipient"]
|
||||
instance = message["subject"]
|
||||
if (instance == "instance %s" % (zephyr_class,) or
|
||||
instance == "test instance %s" % (zephyr_class,)):
|
||||
# Forward messages to e.g. -c -i white-magic back from the
|
||||
# place we forward them to
|
||||
if instance.startswith("test"):
|
||||
instance = zephyr_class
|
||||
zephyr_class = "tabbott-test5"
|
||||
else:
|
||||
instance = zephyr_class
|
||||
zephyr_class = "message"
|
||||
zeph = zephyr.ZNotice(sender=sender_email, auth=True,
|
||||
cls=zephyr_class, instance=instance)
|
||||
body = "%s\0%s" % (zsig, wrapped_content)
|
||||
zeph.setmessage(body)
|
||||
zeph.send()
|
||||
elif message['type'] == "personal":
|
||||
recipient = message["display_recipient"]["email"]
|
||||
recipient = recipient.replace("@mit.edu", "@ATHENA.MIT.EDU")
|
||||
zeph = zephyr.ZNotice(sender=sender_email,
|
||||
auth=True, recipient=recipient,
|
||||
cls="message", instance="personal")
|
||||
body = "%s\0%s" % (zsig, wrapped_content)
|
||||
zeph.setmessage(body)
|
||||
zeph.send()
|
||||
elif message['type'] == "huddle":
|
||||
cc_list = ["CC:"]
|
||||
cc_list.extend([user["email"].replace("@mit.edu", "")
|
||||
for user in message["display_recipient"]])
|
||||
body = "%s\0%s\n%s" % (zsig, " ".join(cc_list), wrapped_content)
|
||||
for r in message["display_recipient"]:
|
||||
recipient = r["email"].replace("mit.edu", "ATHENA.MIT.EDU")
|
||||
zeph = zephyr.ZNotice(sender=sender_email, auth=True,
|
||||
recipient=recipient, cls="message",
|
||||
instance="personal")
|
||||
zeph.setmessage(body)
|
||||
zeph.send()
|
||||
|
||||
def maybe_forward_to_zephyr(message):
|
||||
if message["sender_email"] == options.user + "@mit.edu":
|
||||
timestamp_now = datetime.datetime.now().strftime("%s")
|
||||
if float(message["timestamp"]) < float(timestamp_now) - 15:
|
||||
print "%s humbug=>zephyr: Alert! Out of order message: %s < %s" % \
|
||||
(datetime.datetime.now(), message["timestamp"], timestamp_now)
|
||||
return
|
||||
forward_to_zephyr(message)
|
||||
|
||||
def humbug_to_zephyr(options):
|
||||
# Sync messages from zephyr to humbug
|
||||
print "%s: humbug=>zephyr: Starting syncing messages." % (datetime.datetime.now(),)
|
||||
humbug_client.call_on_each_message(maybe_forward_to_zephyr,
|
||||
options={"mirror": 'zephyr_mirror'})
|
||||
|
||||
def subscribed_to_mail_messages():
|
||||
for (cls, instance, recipient) in parse_zephyr_subs(verbose=False):
|
||||
if (cls.lower() == "mail" and instance.lower() == "inbox"):
|
||||
return True
|
||||
return False
|
||||
|
||||
def add_humbug_subscriptions():
|
||||
zephyr_subscriptions = set()
|
||||
for (cls, instance, recipient) in parse_zephyr_subs(verbose=options.verbose):
|
||||
if cls == "message" and recipient == "*":
|
||||
if instance == "*":
|
||||
continue
|
||||
# If you're on -i white-magic on zephyr, get on stream white-magic on humbug
|
||||
# instead of subscribing to stream message
|
||||
zephyr_subscriptions.add(instance)
|
||||
continue
|
||||
elif instance != "*" or recipient != "*":
|
||||
if options.verbose:
|
||||
print "Skipping ~/.zephyr.subs line: [%s,%s,%s]: Non-* values" % \
|
||||
(cls, instance, recipient)
|
||||
continue
|
||||
zephyr_subscriptions.add(cls)
|
||||
if len(zephyr_subscriptions) != 0:
|
||||
humbug_client.subscribe(list(zephyr_subscriptions))
|
||||
|
||||
def parse_zephyr_subs(verbose=False):
|
||||
if verbose:
|
||||
print "Adding your ~/.zephyr.subs subscriptions to Humbug!"
|
||||
zephyr_subscriptions = set()
|
||||
subs_file = os.path.join(os.environ["HOME"], ".zephyr.subs")
|
||||
if not os.path.exists(subs_file):
|
||||
if verbose:
|
||||
print >>sys.stderr, "Couldn't find .zephyr.subs!"
|
||||
print >>sys.stderr, "Do you mean to run with --no-auto-subscribe?"
|
||||
return []
|
||||
|
||||
for line in file(subs_file, "r").readlines():
|
||||
line = line.strip()
|
||||
if len(line) == 0:
|
||||
continue
|
||||
try:
|
||||
(cls, instance, recipient) = line.split(",")
|
||||
except:
|
||||
if verbose:
|
||||
print >>sys.stderr, "Couldn't parse ~/.zephyr.subs line: [%s]" % (line,)
|
||||
continue
|
||||
zephyr_subscriptions.add((cls.strip(), instance.strip(), recipient.strip()))
|
||||
return zephyr_subscriptions
|
||||
|
||||
if options.forward_from_humbug:
|
||||
print "This option is obsolete."
|
||||
sys.exit(0)
|
||||
|
||||
child_pid = os.fork()
|
||||
if child_pid == 0:
|
||||
# Run the humbug => zephyr mirror in the child
|
||||
import zephyr
|
||||
zephyr.init()
|
||||
humbug_to_zephyr(options)
|
||||
sys.exit(0)
|
||||
|
||||
import zephyr
|
||||
zephyr.init()
|
||||
subs = zephyr.Subscriptions()
|
||||
zephyr_to_humbug(options)
|
Loading…
Add table
Add a link
Reference in a new issue