source: trollforge/troll/dramabot (older).py @ 386

Revision 307, 7.3 KB checked in by incog, 3 years ago (diff)
Line 
1# dramabot
2# a text generation IRC technology
3# by rolloffle, 2006
4
5from random import choice, randrange
6from re import compile
7from socks import socks4a  # if using Tor on 127.0.0.1:9050
8import threading
9from time import sleep
10
11DENOUEMENTS = ('oops', 'oh hi', 'oh... hi', 'eurgh, shit', 'oh shit', 'oh fuck', 'speak of the devil', 'good timing', 'well this is akward, heh', 'this is awkward...')
12INSULTS = (
13        '%s is such a fat faggot',
14        '%s is such a faggot',
15        '%s\'s a fucking tool',
16        '%s is a judenspy',
17        'good thing %s isn\'t here to see that',
18        'im gonna tell %s you said that',
19        'tell %s to fuck off already',
20        '%s is a complete attention whore',
21        '%s is a worthless jew, why do we even keep him around?',
22        'who the fuck invited %s here',
23        '%s is a useless goblinkike',
24        'nobody wants %s around but don\'t mention it',
25        '%s is a complete cocksucking aspie',
26        'i know exactly what you mean about %s',
27        'did you hear the rumours about %s?',
28        '%s is a loser too',
29        'but I won\'t tell %s you said that',
30)
31OPENINGS = (
32        'yeah, %s,',
33        'yeah %s',
34        'totally %s,',
35        'srsly %s,',
36        'agree 100%%, %s,',
37        'agreed %s,',
38        '%s backs me up on this,',
39        'yah, %s told me,',
40        'i agree %s,'
41)
42
43def rand_char():
44        return chr(randrange(ord('a'), ord('z')))
45
46def gen_rand_username():
47        return 'wqat'
48        #return ''.join([rand_char() for i in range(8)])
49
50class channel:
51
52        def __init__(self, con, chan):
53                """Initialise, join the channel."""
54
55                self.con = con
56                self.chan = chan
57                self.nicks = [ ]
58                self.con.lsend('JOIN ' + chan)
59
60        def rand_nick(self):
61                """Returns a random nick present in this channel."""
62                return choice(self.nicks)
63
64        def strip_nick_status_symbol(self, nick):
65                """If present, removes the status character from a nick."""
66                if nick[0] in '@%+':
67                        nick = nick[1:]
68                return nick
69
70        def add_nicks(self, nicks):
71                """Add a list of nicks to this channel's nick list."""
72                for nick in nicks:
73                        nick = self.strip_nick_status_symbol(nick)
74                        if (nick != self.con.nick) and (nick not in self.nicks):
75                                self.nicks += [ nick ]
76
77        def del_nick(self, nick):
78                """Delete a nick from this channel's nick list."""
79                nick = self.strip_nick_status_symbol(nick)
80                try:
81                        self.nicks.remove(nick)
82                except:
83                        print 'Error: failed to remove \'%s\' from nick list for %s' % (nick, self.chan)
84
85        def drama_bomb(self, target):
86                """Say something in the channel to a target nick to provoke them."""
87                global DENOUEMENTS, INSULTS, OPENINGS
88
89                template = 'PRIVMSG %s :' + choice(OPENINGS) + ' ' + choice(INSULTS)
90                print "TEMPLATE: " + template
91                bomb = template % (self.chan, self.rand_nick(), target)
92
93                print '%s: drama bomb "%s"' % (self.chan, bomb)
94                self.con.lsend(bomb)
95
96                if randrange(1, 2) != 1:
97                        # chance of saying a denouement
98                        sleep(1)
99                        self.con.lsend('PRIVMSG %s :%s' % (self.chan, choice(DENOUEMENTS)))
100
101        def display_status(self):
102                """Write a status report for this channel on stdout."""
103                print %s: new nick list length %u' % (self.chan, len(self.nicks))
104
105class con:
106
107        def __init__(self, server, port, channels, nick, socks4a_proxy = None):
108
109                self.server, self.port, self.nick = server, port, nick
110
111                self.r = { }
112                self.r['001'] = compile(':[^ ]+ 001 ')
113                self.r['353'] = compile(':[^ ]+ 353 [^ ]+ . ([^ ]+) :(.+)')
114                self.r['433'] = compile(':[^ ]+ 433 . [^ ]+ :.+')
115                self.r['join'] = compile(':([^!~:]+)![^ ]+ JOIN :([^ ]+)')
116                self.r['part'] = compile(':([^!~:]+)![^ ]+ PART ([^ ]+)( :(.+))?')
117                self.r['kick'] = compile(':([^!~:]+)![^ ]+ KICK ([^ ]+) ([^ ]+)( :(.+))?')
118                self.r['privmsg'] = compile(':([^!~:]+)![^ ]+ PRIVMSG ([^ ]+) :(.+)')
119
120                self.connect(socks4a_proxy)
121
122                self.channels = { }
123                for chan in channels:
124                        self.channels[chan] = channel(self, chan)
125
126        def lsend(self, s):
127                self.sock.send(s + '\r\n')
128
129        def lrecv(self):
130                c, s = '', ''
131                while c != '\n':
132                        c = self.sock.recv(1)
133                        if c == '':  # connection closed
134                                break
135                        s += c
136                return s.strip('\r\n')
137
138        def connect(self, socks4a_proxy = None):
139                """Make the initial connection to the server and try to register."""
140
141                self.sock = socks4a()
142
143                print 'Connecting to %s:%u' % (self.server, self.port)
144                if socks4a_proxy == None:
145                        self.sock.connect((self.server, self.port))
146                else:
147                        self.sock.proxy_connect(socks4a_proxy, (self.server, self.port))
148
149                username = gen_rand_username()
150                print '  username = ' + username
151                self.lsend('USER ' + username + ' 0 0 :Unknown')
152                self.lsend('NICK ' + self.nick + ' 0')
153
154                # Wait for the 001 status reply.
155                while 1:
156                        line = self.lrecv()
157                        if self.r['001'].match(line):
158                                # We got the 001, break out of the loop and proceed.
159                                break
160                        elif self.r['433'].match(line):
161                                # This nick is taken. Change the last 2 chars and retry.
162                                self.nick = self.nick[:-2] + rand_char() + rand_char()
163                                self.lsend('NICK ' + self.nick + ' 0')
164                        elif line == '':
165                                raise 'ConnectError', (self.server, self.port, 'EOFBefore001')
166
167                print '  got 001'
168
169        def go(self):
170
171                global rand_char
172
173                # Join the channels.
174                print '  joining channels'
175                for channel in self.channels:
176                        self.lsend('JOIN ' + channel)
177                print '  joined all channels'
178
179                # Sit and watch at the socket for incoming data and act on it.
180
181                while 1:
182
183                        line = self.lrecv()
184
185                        if line == '':
186                                raise 'ConnectionClose', (self.server, self.port)
187
188                        elif line[:6] == 'PING :':
189                                print '  PONG :' + line[6:]
190                                self.lsend('PONG :' + line[6:])
191                                continue
192
193                        m = self.r['join'].match(line)
194                        if m != None:
195                                # Somebody joined. If it's not us, start the drama and add
196                                # their nick to the master list of nicks in this channel.
197                                print 'Received: JOIN'
198
199                                if m.group(1) == self.nick:
200                                        continue
201
202                                chan = self.channels[m.group(2)]
203
204                                chan.add_nicks([ m.group(1) ])
205                                chan.display_status()
206                                chan.drama_bomb(m.group(1))
207                               
208                                continue
209
210                        m = self.r['part'].match(line)
211                        if m != None:
212                                # Somebody parted, remove their nick from the master list of
213                                # this channel's nicks.
214                                print 'Received: PART'
215                                chan = self.channels[m.group(2)]
216                                chan.del_nick(m.group(1))
217                                chan.display_status()
218
219                        m = self.r['353'].match(line)
220                        if m != None:
221                                # 353 lists the nicks of the user in a channel we just
222                                # joined. Add the list of nicks given to the master list of
223                                # nicks present in the channel.
224                                print 'Received: 353'
225                                chan = self.channels[m.group(1)]
226                                chan.add_nicks(m.group(2).split())
227                                chan.display_status()
228                                continue
229
230                        m = self.r['kick'].match(line)
231                        if m != None:
232                                # Someone was kicked.
233                                if m.group(3) == self.nick:
234                                        # It was us! Rejoin.
235                                        print 'Kicked! Attempting to rejoin ' + m.group(2)
236                                        self.lsend('JOIN ' + m.group(2))
237                                continue
238
239class con_thread(threading.Thread):
240
241        def __init__(self, server, port, channels, nick):
242                self.co = con(server, port, channels, nick)
243                threading.Thread.__init__(self)
244
245        def run(self):
246                self.co.go()
247                #self.co.go(('127.0.0.1', 9050))  # connect via Tor
248
249threads = [
250        con_thread('irc.buttes.org', 6667, ['#cockes'], 'orangedrink'),
251        #con_thread('irc.chir.pn', 6667, ['#chirp'], 'dramabot')
252
253        # The wacky .onion hostname is because it's Freenode's hidden Tor service
254        #con_thread('mejokbp2brhw4omd.onion', 6667, ['#wikipedia'], 'fade')
255]
256
257for thread in threads:
258        thread.start()
Note: See TracBrowser for help on using the repository browser.