-
Notifications
You must be signed in to change notification settings - Fork 5
/
get_message
executable file
·114 lines (100 loc) · 3.7 KB
/
get_message
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
#!/usr/bin/python
import hesiod
import os
import select
import socket
import sys
from optparse import OptionParser
MESSAGE_VERS = 'GMS:0'
MESSAGE_SIZE = 2048
MESSAGE_CACHE = '/var/cache/libgms/messages'
MESSAGE_TIMEOUT = 5
GMS_USERFILE = '.message_times'
GMS_PORT = 2106
def get_server():
"""Look up the globalmessage service in Hesiod, to get a server to connect to."""
try:
return hesiod.Lookup('globalmessage', 'sloc').results[0]
except:
raise Exception('Unable to lookup gms server')
def parse(msg):
"""Parse a gms message, returning a version, timestamp, text tuple
if successful, and an Exception otherwise."""
try:
header, text = msg.split('\n', 1)
version, timestamp = header.split(' ', 1)
if version != MESSAGE_VERS:
raise Exception('Incompatible version of GMS [%s] found' % (version,))
return (version, int(timestamp), text)
except:
raise Exception('Unable to parse the specified message')
def get_message_times():
return os.path.expanduser(os.path.join('~', GMS_USERFILE))
def has_seen(timestamp):
"""Check if the user has seen this message, by reading
~/.message_times. If this file cannot be read, assume no."""
try:
with open(get_message_times(), 'r') as mtimes:
_, lastread, _ = parse(mtimes.read())
return timestamp <= lastread
except:
return False
def write_message_times(timestamp):
"""Write ~/.message_times with the specified timestamp."""
try:
with open(get_message_times(), 'w') as mtimes:
mtimes.write('%s %d\n' % (MESSAGE_VERS, timestamp))
except:
# The write failed. All this means is the user will see the
# message again later.
pass
def fetch_message():
"""Connect to the globalmessage server, and read a message."""
server = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
server.sendto('%s 0\n' % (MESSAGE_VERS,), (get_server(), GMS_PORT))
message = None
readable, _, _ = select.select([server], [], [], MESSAGE_TIMEOUT)
for i in readable:
message, _ = i.recvfrom(MESSAGE_SIZE)
return message
def save_message_to_cache(msg_tuple):
"""Save the specified message to the cache."""
with open(MESSAGE_CACHE, 'w') as f:
f.write('%s %d\n%s' % msg_tuple)
def read_message_from_cache():
with open(MESSAGE_CACHE, 'r') as f:
return f.read()
def get_message():
msg = fetch_message()
if msg is not None:
# Save the message to the cache, if it parses
msg_tuple = parse(msg)
save_message_to_cache(msg_tuple)
else:
# Huh, no message. Try to read it from cache
msg = read_message_from_cache()
return parse(msg)
def main():
# Make flags
parser = OptionParser()
parser.add_option("-n", action="store_true", dest="new", default=False)
parser.add_option("-l", action="store_true", dest="login", default=False)
parser.add_option("-z", action="store_true", dest="zephyr", default=False)
# This is why we can't have nice things
old_args = { '-new': '-n',
'-login': '-l',
'-zephyr': '-z' }
options, args = parser.parse_args(
[old_args.get(x, x) for x in sys.argv[1:]])
if options.zephyr:
print >>sys.stderr, "get_message: The -z/-zephyr option is deprecated."
version, timestamp, content = get_message()
if options.new and has_seen(timestamp):
# This is an already-seen message, and new-only was requested.
sys.exit(0)
if not options.login:
# Update the timestamp so we know this message has been seen
write_message_times(timestamp)
print content
if __name__ == "__main__":
main()