| 1 | import re |
|---|
| 2 | from sys import exit |
|---|
| 3 | import socket |
|---|
| 4 | import threading |
|---|
| 5 | from time import sleep |
|---|
| 6 | |
|---|
| 7 | ###################### |
|---|
| 8 | # global config vars # |
|---|
| 9 | ###################### |
|---|
| 10 | |
|---|
| 11 | chanfile = 'chans.txt' |
|---|
| 12 | nick = 'gayngr' |
|---|
| 13 | nickfile = 'nicks.txt' |
|---|
| 14 | seedchans = [ '#wtfux', '#gay-nigger-orgy' ] |
|---|
| 15 | server = ( 'wtfuxnet.ath.cx', '6667' ) |
|---|
| 16 | |
|---|
| 17 | ####################### |
|---|
| 18 | # global program vars # |
|---|
| 19 | ####################### |
|---|
| 20 | |
|---|
| 21 | allchans = [ ] |
|---|
| 22 | allnicks = [ ] |
|---|
| 23 | qc = seedchans |
|---|
| 24 | qn = [ ] |
|---|
| 25 | |
|---|
| 26 | ###################### |
|---|
| 27 | # thread definitions # |
|---|
| 28 | ###################### |
|---|
| 29 | |
|---|
| 30 | class actupon(threading.Thread): |
|---|
| 31 | # this thread acts upon the incoming data, deciding what to do next |
|---|
| 32 | |
|---|
| 33 | def run(self): |
|---|
| 34 | global qc |
|---|
| 35 | global qn |
|---|
| 36 | global sock |
|---|
| 37 | |
|---|
| 38 | lastchan = '' |
|---|
| 39 | |
|---|
| 40 | while 1: |
|---|
| 41 | |
|---|
| 42 | # drop into the next channel if there are any left to visit |
|---|
| 43 | if len(qc): |
|---|
| 44 | |
|---|
| 45 | print len(qc), len(qn) |
|---|
| 46 | |
|---|
| 47 | if lastchan != '': |
|---|
| 48 | print 'PART ' + lastchan |
|---|
| 49 | sock.send('PART ' + lastchan + '\r\n') |
|---|
| 50 | sleep(1.1) |
|---|
| 51 | |
|---|
| 52 | lastchan = qc.pop() |
|---|
| 53 | print 'JOIN ' + lastchan |
|---|
| 54 | sock.send('JOIN ' + lastchan + '\r\n') |
|---|
| 55 | sleep(1.5) |
|---|
| 56 | continue |
|---|
| 57 | |
|---|
| 58 | elif len(qn): |
|---|
| 59 | # we've run out of channels, /whois to find some more |
|---|
| 60 | sock.send('WHOIS ' + qn.pop() + '\r\n') |
|---|
| 61 | sleep(1.4) |
|---|
| 62 | continue |
|---|
| 63 | |
|---|
| 64 | # hmm, no nicks or chans - let's wait for some to come in |
|---|
| 65 | sleep(2) |
|---|
| 66 | |
|---|
| 67 | class watchsock(threading.Thread): |
|---|
| 68 | # this thread watches the socket and sorts incoming data |
|---|
| 69 | |
|---|
| 70 | global chanfile |
|---|
| 71 | global nickfile |
|---|
| 72 | global server |
|---|
| 73 | |
|---|
| 74 | cfile = open(chanfile, 'w', 1) |
|---|
| 75 | nfile = open(nickfile, 'w', 1) |
|---|
| 76 | |
|---|
| 77 | serv = ':' + server[0] |
|---|
| 78 | r = ( |
|---|
| 79 | re.compile(serv + ' 319 ' + nick + ' .+ :(.+)'), |
|---|
| 80 | re.compile(serv + ' 353 ' + nick + ' [^ ]+ #[^ ]+ :(.+)') |
|---|
| 81 | ) |
|---|
| 82 | |
|---|
| 83 | def getchans(self, line): |
|---|
| 84 | global nick |
|---|
| 85 | chans = [ ] |
|---|
| 86 | mtch = self.r[0].search(line) |
|---|
| 87 | if mtch != None: |
|---|
| 88 | for chan in mtch.group(1).split(): |
|---|
| 89 | chan = chan.strip() |
|---|
| 90 | while chan[0] == '@' or chan[0] == '%' or chan[0] == '+': |
|---|
| 91 | chan = chan[1:] |
|---|
| 92 | if chan != '': |
|---|
| 93 | if chan[0] == '#' or chan[0] == '&': |
|---|
| 94 | chans.append(chan) |
|---|
| 95 | chans.sort() |
|---|
| 96 | return chans |
|---|
| 97 | else: |
|---|
| 98 | return [ ] |
|---|
| 99 | |
|---|
| 100 | def getnicks(self, line): |
|---|
| 101 | global nick |
|---|
| 102 | nicks = [ ] |
|---|
| 103 | mtch = self.r[1].search(line) |
|---|
| 104 | if mtch != None: |
|---|
| 105 | for cnick in mtch.group(1).split(): |
|---|
| 106 | cnick = cnick.strip() |
|---|
| 107 | while cnick[0] == '@' or cnick[0] == '%' or cnick[0] == '+': |
|---|
| 108 | cnick = cnick[1:] |
|---|
| 109 | if cnick != '' and cnick != nick: |
|---|
| 110 | nicks.append(cnick) |
|---|
| 111 | nicks.sort() |
|---|
| 112 | return nicks |
|---|
| 113 | else: |
|---|
| 114 | return [ ] |
|---|
| 115 | |
|---|
| 116 | def run(self): |
|---|
| 117 | global allchans |
|---|
| 118 | global allnicks |
|---|
| 119 | global nick |
|---|
| 120 | global qc |
|---|
| 121 | global qn |
|---|
| 122 | global sock |
|---|
| 123 | |
|---|
| 124 | while 1: |
|---|
| 125 | |
|---|
| 126 | buf = sock.recv(1) |
|---|
| 127 | try: |
|---|
| 128 | while buf[-1] != '\r' and buf[-1] != '\n': |
|---|
| 129 | buf += sock.recv(1) |
|---|
| 130 | except: |
|---|
| 131 | sock.close() |
|---|
| 132 | self.cfile.close() |
|---|
| 133 | self.nfile.close() |
|---|
| 134 | exit(3) |
|---|
| 135 | |
|---|
| 136 | if buf.strip() == '': |
|---|
| 137 | continue |
|---|
| 138 | |
|---|
| 139 | if buf.find('ERROR :Closing Link: ') != -1: |
|---|
| 140 | print buf |
|---|
| 141 | exit(4) |
|---|
| 142 | |
|---|
| 143 | # reply to PINGs |
|---|
| 144 | if (buf[:6] == 'PING :'): |
|---|
| 145 | sock.send('PONG :' + buf[6:] + '\r\n') |
|---|
| 146 | continue |
|---|
| 147 | |
|---|
| 148 | # 319: harvest channels from a whois |
|---|
| 149 | if buf.find(self.serv + ' 319 ' + nick + ' ') != -1: |
|---|
| 150 | chans = self.getchans(buf) |
|---|
| 151 | for chan in chans: |
|---|
| 152 | if chan not in allchans: |
|---|
| 153 | self.cfile.write(chan + '\n') |
|---|
| 154 | qc.append(chan) |
|---|
| 155 | allchans.append(chan) |
|---|
| 156 | allchans.sort() |
|---|
| 157 | |
|---|
| 158 | # 353: harvest nicknames from channel joins |
|---|
| 159 | if buf.find(self.serv + ' 353 ' + nick + ' ') != -1: |
|---|
| 160 | nicks = self.getnicks(buf) |
|---|
| 161 | for cnick in nicks: |
|---|
| 162 | if cnick not in allnicks: |
|---|
| 163 | self.nfile.write(cnick + '\n') |
|---|
| 164 | qn.append(cnick) |
|---|
| 165 | allnicks.append(cnick) |
|---|
| 166 | allnicks.sort() |
|---|
| 167 | |
|---|
| 168 | ################ |
|---|
| 169 | # main program # |
|---|
| 170 | ################ |
|---|
| 171 | |
|---|
| 172 | sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) |
|---|
| 173 | sock.connect((server[0], int(server[1]))) |
|---|
| 174 | sock.send('USER ' + nick + ' 0 0 :Gary Niger\r\n') |
|---|
| 175 | sock.send('NICK ' + nick + '\r\n') |
|---|
| 176 | |
|---|
| 177 | # wait for 376 before JOINING |
|---|
| 178 | while 1: |
|---|
| 179 | |
|---|
| 180 | try: |
|---|
| 181 | buf = sock.recv(1024) |
|---|
| 182 | except: |
|---|
| 183 | sock.close() |
|---|
| 184 | exit(1) |
|---|
| 185 | |
|---|
| 186 | if (buf[:6] == 'PING :'): |
|---|
| 187 | sock.send('PONG :' + buf[6:] + '\r\n') |
|---|
| 188 | |
|---|
| 189 | if buf.find(':' + server[0] + ' 376 ') != -1: |
|---|
| 190 | # got 376, continue |
|---|
| 191 | break |
|---|
| 192 | |
|---|
| 193 | if buf.find('ERROR :Closing Link:') == 0: |
|---|
| 194 | print buf |
|---|
| 195 | exit(2) |
|---|
| 196 | |
|---|
| 197 | # start watching for incoming chans and nicks |
|---|
| 198 | watchthread = watchsock() |
|---|
| 199 | watchthread.start() |
|---|
| 200 | |
|---|
| 201 | # crawl! |
|---|
| 202 | actthread = actupon() |
|---|
| 203 | actthread.start() |
|---|
| 204 | |
|---|
| 205 | # just run until something blows up |
|---|
| 206 | while threading.activeCount() > 1: |
|---|
| 207 | sleep(0.6) |
|---|