tox_irc_sync/tox-irc-sync.py

624 lines
22 KiB
Python
Raw Normal View History

2013-12-01 15:09:54 +00:00
import sys
2022-10-23 22:11:12 +00:00
import os
2013-12-01 15:09:54 +00:00
import socket
import string
import select
import re
2014-02-20 11:38:20 +00:00
import pickle
2022-10-23 22:11:12 +00:00
import logging
import readline
import ctypes
2013-12-01 15:09:54 +00:00
from time import sleep
from os.path import exists
2014-04-06 00:16:18 +00:00
from threading import Thread
2022-10-23 22:11:12 +00:00
from random import shuffle
2013-12-01 15:09:54 +00:00
2022-10-23 22:11:12 +00:00
import wrapper
from wrapper.tox import Tox
from wrapper.toxav import ToxAV
import wrapper.toxcore_enums_and_consts as enums
from wrapper.toxcore_enums_and_consts import \
TOX_CONNECTION, TOX_USER_STATUS, TOX_MESSAGE_TYPE, \
TOX_SECRET_KEY_SIZE, TOX_FILE_CONTROL, TOX_ADDRESS_SIZE, \
TOX_GROUP_PRIVACY_STATE, TOX_GROUP_ROLE
try:
import support_testing as ts
except ImportError:
import wrapper_tests.support_testing as ts
2013-12-01 15:09:54 +00:00
2022-10-23 22:11:12 +00:00
global LOG
LOG = logging.getLogger('app.'+'ts')
2013-12-01 15:09:54 +00:00
2022-10-23 22:11:12 +00:00
PWD = ''
NAME = NICK = IDENT = REALNAME = 'SyniTox'
2013-12-01 15:09:54 +00:00
2014-04-06 00:16:18 +00:00
class AV(ToxAV):
2022-10-23 22:11:12 +00:00
def __init__(self, core):
self.core = core
2014-08-05 06:36:03 +00:00
self.cs = None
2022-10-23 22:11:12 +00:00
self.call_type = None
2014-04-06 00:16:18 +00:00
2014-08-05 06:36:03 +00:00
def on_invite(self, idx):
self.cs = self.get_peer_csettings(idx, 0)
2014-08-15 15:10:31 +00:00
self.call_type = self.cs['call_type']
2014-04-09 20:48:24 +00:00
2022-10-23 22:11:12 +00:00
LOG.info('Incoming %s call from %d:%s ...' % (
2014-08-15 15:10:31 +00:00
'video' if self.call_type == self.TypeVideo else 'audio', idx,
2014-08-05 06:36:03 +00:00
self.core.get_name(self.get_peer_id(idx, 0))))
2014-04-09 20:48:24 +00:00
2014-08-05 06:36:03 +00:00
self.answer(idx, self.call_type)
2022-10-23 22:11:12 +00:00
LOG.info('Answered, in call...')
2014-04-09 20:48:24 +00:00
2014-08-05 06:36:03 +00:00
def on_start(self, idx):
2014-08-15 15:10:31 +00:00
self.change_settings(idx, {'max_video_width': 1920,
'max_video_height': 1080})
2014-08-05 06:36:03 +00:00
self.prepare_transmission(idx, self.jbufdc * 2, self.VADd,
True if self.call_type == self.TypeVideo else False)
2014-04-06 00:16:18 +00:00
2014-08-05 06:36:03 +00:00
def on_end(self, idx):
2014-04-06 00:16:18 +00:00
self.kill_transmission()
2014-04-09 20:48:24 +00:00
2022-10-23 22:11:12 +00:00
LOG.info('Call ended')
2014-04-06 00:16:18 +00:00
2014-08-05 06:36:03 +00:00
def on_peer_timeout(self, idx):
2014-04-06 00:16:18 +00:00
self.stop_call()
2014-08-05 06:36:03 +00:00
def on_audio_data(self, idx, size, data):
sys.stdout.write('.')
sys.stdout.flush()
self.send_audio(idx, size, data)
2014-04-06 00:16:18 +00:00
2014-08-05 06:36:03 +00:00
def on_video_data(self, idx, width, height, data):
sys.stdout.write('*')
sys.stdout.flush()
self.send_video(idx, width, height, data)
2014-04-06 00:16:18 +00:00
2022-10-23 22:11:12 +00:00
bot_toxname = 'SyniTox'
class SyniTox(Tox):
def __init__(self, opts,
sChannel='#tor',
sIRC_HOST='irc.oftc.net',
iIRC_PORT=6667,
GROUP_BOT_PK = '',
sMEMORY_DB = ''
):
Tox.__init__(self, tox_options=opts)
self._address = self.self_get_address()
self._opts = opts
self._app = None
self._settings = {}
self._sChannel = sChannel
self.sIRC_HOST = sIRC_HOST
self.iIRC_PORT = iIRC_PORT
self.sGROUP_BOT_PK = GROUP_BOT_PK
self.sMEMORY_DB = sMEMORY_DB
global oTOX_OARGS
self._oArgs = oTOX_OARGS
data = self._oArgs.profile
if data and os.path.exists(data):
self.load_from_file(data)
self.av = self.AV
self.irc = None
self.bid = -1
self._bRouted = None
def start(self):
self.self_set_name(bot_toxname)
self.self_set_status_message("Send me a message with the word 'invite'")
LOG.info('Our ToxID: %s' % self.self_get_toxid())
self.readbuffer = b''
2013-12-01 15:09:54 +00:00
self.tox_group_id = None
2022-10-23 22:11:12 +00:00
self.group_init()
2014-02-20 11:27:49 +00:00
self.memory = {}
2022-10-23 22:11:12 +00:00
if os.path.exists(self.sMEMORY_DB):
with open(self.sMEMORY_DB, 'r') as f:
2014-02-20 11:38:20 +00:00
self.memory = pickle.load(f)
2022-10-23 22:11:12 +00:00
self.irc_init()
b = self.test_net()
if b:
self.dht_init()
def bRouted(self):
if self._oArgs.network not in ['local', 'localnew', 'newlocal']:
b = ts.bAreWeConnected()
if b is None:
i = os.system('ip route|grep ^def')
if i > 0:
b = False
else:
b = True
if not b:
LOG.warn("No default route for network " +self._oArgs.network)
return False
return b
return True
def test_net(self, lElts=None, oThread=None, iMax=4):
# bootstrap
lNodes = ts.generate_nodes(oArgs=self._oArgs,
ipv='ipv4',
udp_not_tcp=True)
self._settings['current_nodes_udp'] = lNodes.copy()
if not lNodes:
LOG.warn('empty generate_nodes udp')
else:
LOG.debug(f'Called generate_nodes: udp {len(lNodes)}')
lNodes = ts.generate_nodes(oArgs=self._oArgs,
ipv='ipv4',
udp_not_tcp=False)
self._settings['current_nodes_tcp'] = lNodes
if not lNodes:
LOG.warn('empty generate_nodes tcp')
else:
LOG.debug(f'Called generate_nodes: tcp {len(lNodes)}')
# if oThread and oThread._stop_thread: return
LOG.debug("test_net network=" +self._oArgs.network +' iMax=' +str(iMax))
return True
def group_init(self):
LOG.debug(f"group_init proxy={self._oArgs.proxy_type}")
group_name = bot_toxname +' Test ' +self._sChannel
if not self.sGROUP_BOT_PK:
privacy_state = TOX_GROUP_PRIVACY_STATE['PUBLIC']
nick = bot_toxname +self._sChannel
status = TOX_USER_STATUS['NONE']
num = self.group_new(privacy_state, group_name, nick, status)
assert num >= 0, num
pk = self.group_self_get_public_key(num)
assert pk, pk
self.sGROUP_BOT_PK = pk
self.sGROUP_NUM = num
self.group_set_topic(num, bot_toxname +" IRC")
LOG.info(f"group_init GROUP_BOT_PK={self.sGROUP_BOT_PK}")
#? self.tox_group_id = self.bid
self.group_send_message(num, TOX_MESSAGE_TYPE['NORMAL'], "hi")
# TOX_GROUP_ROLE['FOUNDER']
self.init_callbacks()
def init_callbacks(self):
def gi_wrapped(iTox, friendid, invite_data, invite_len, *args):
invite_data = str(invite_data, 'UTF-8')
self.on_group_invite(friendid, invite_data)
self.callback_group_invite(gi_wrapped, 0)
def scs_wrapped(iTox, friendid, *args):
self.on_connection_status(self, scs_wrapped)
self.callback_self_connection_status(scs_wrapped)
def gm_wrapped(iTox, groupnumber, peer_id, type_, message, mlen, *args):
message = str(message, 'UTF-8')
self.on_group_message(groupnumber, peer_id, message)
self.callback_group_message(gm_wrapped, 0)
def ga_wrapped(iTox, groupnumber, peer_id, type_, action, mlen, *args):
self.on_group_action(groupnumber, peer_id, action)
#? self.callback_group_action(ga_wrapped, 0)
def fr_wrapped(iTox, pk, message, mlen, *args):
message = str(message, 'UTF-8')
self.on_friend_request(self, pk, message)
self.callback_friend_request(fr_wrapped)
def fm_wrapped(iTox, peer_id, message, mlen, *args):
message = str(message, 'UTF-8')
self.on_friend_request(self, peer_id, message)
self.callback_friend_request(fm_wrapped)
def del_callbacks(self):
self.callback_group_invite(None, 0)
self.callback_self_connection_status(None)
self.callback_group_message(None, 0)
# self.callback_group_action(None, 0)
self.callback_friend_request(None)
self.callback_friend_request(None)
def irc_init(self):
2022-10-23 22:11:12 +00:00
if not self.bRouted(): return
LOG.info(f"irc_init proxy={self._oArgs.proxy_type}")
if self._oArgs.proxy_type == 2:
from wrapper_tests import socks
socks.setdefaultproxy(socks.PROXY_TYPE_SOCKS5,
self._oArgs.proxy_host,
self._oArgs.proxy_port)
irc = socks.socksocket()
else:
irc = socket.socket()
try:
irc.connect((self.sIRC_HOST, self.iIRC_PORT))
irc.send(bytes('NICK ' + NICK + '\r\n', 'UTF-8' ))
irc.send(bytes('USER %s %s bla :%s\r\n' % (IDENT, self.sIRC_HOST, REALNAME),
'UTF-8'))
except Exception as e:
LOG.warn(f'IRC error {e}')
else:
LOG.info('IRC connected ' +'NICK =' + NICK)
self.irc = irc
def dht_init(self):
if not self.bRouted(): return
if 'current_nodes_udp' not in self._settings:
self.test_net()
lNodes = self._settings['current_nodes_udp']
shuffle(lNodes)
if self._oArgs.proxy_type == 0:
ts.bootstrap_good(lNodes[:4], [self])
else:
if self._bRouted == None:
LOG.info(f'DHT bootstapping 1')
ts.bootstrap_good([lNodes[0]], [self])
if 'current_nodes_tcp' not in self._settings:
self.test_net()
lNodes = self._settings['current_nodes_tcp']
shuffle(lNodes)
ts.bootstrap_tcp(lNodes[:4], [self])
def ensure_exe(self, func, *args):
2013-12-11 15:55:40 +00:00
count = 0
2013-12-11 16:02:01 +00:00
THRESHOLD = 50
2013-12-11 15:55:40 +00:00
while True:
try:
return func(*args)
except:
assert count < THRESHOLD
count += 1
2022-10-23 22:11:12 +00:00
self.do()
2013-12-01 15:09:54 +00:00
2022-10-23 22:11:12 +00:00
def do(self, n=50):
interval = self.iteration_interval()
for i in range(n):
self.iterate()
sleep(interval / 1000.0 *10)
def unroute(self):
if self.irc:
try: irc.close()
except: pass
self.irc = None
def irc_check(self, lines):
if b'NOTICE AUTH' in lines[0]:
for line in lines[:99]:
if b'NOTICE AUTH' not in line: return
line = str(line, 'UTF-8').strip()
print(line)
else:
for line in lines[:5]:
line = str(line, 'UTF-8').strip().lower()
if 'banned' in line:
raise RuntimeError(line)
if 'error' in line and 'closing' in line:
raise RuntimeError(line)
def iLoop(self):
2013-12-01 15:09:54 +00:00
checked = False
self.joined = False
2013-12-11 16:02:01 +00:00
self.request = False
2022-10-23 22:11:12 +00:00
count = 0
2013-12-01 15:09:54 +00:00
try:
2022-10-23 22:11:12 +00:00
count = count + 1
2013-12-01 15:09:54 +00:00
while True:
2022-10-23 22:11:12 +00:00
b = self.bRouted()
if not b:
self.unroute()
checked = False
if self._bRouted is None or self._bRouted != b:
self._bRouted = b
if count % 6 == 1:
LOG.info(f'Not routed {count}')
sleep(10)
continue
else:
if self._bRouted is None:
self._bRouted = True
self.irc_send('.')
if self._bRouted is None or self._bRouted != b:
self._bRouted = b
LOG.debug(f'Routed {count}')
status = self.self_get_connection_status()
if not status:
if count % 6 == 1:
LOG.info(f'Not connected {count}')
self.dht_init()
if b and not checked and status:
LOG.info('Connected to DHT.')
2013-12-01 15:09:54 +00:00
checked = True
2013-12-11 16:02:01 +00:00
try:
2022-10-23 22:11:12 +00:00
self.bid = self.friend_by_public_key(self.sGROUP_BOT_PK)
LOG.info(f'Connected to group {self.bid}')
except ctypes.ArgumentError as e:
self.bid = None
if self.bid == None:
self.ensure_exe(self.friend_add_norequest, self.sGROUP_BOT_PK)
LOG.info(f'friend_add_n to group {self.sGROUP_BOT_PK[:8]}')
self.bid = self.friend_by_public_key(self.sGROUP_BOT_PK)
LOG.info(f'Added to group {self.bid}')
num = self.sGROUP_NUM
my_pk = self.group_self_get_public_key(num)
LOG.info(f'Connected to group as {my_pk[:8]}')
if b and checked and not status:
LOG.info('Disconnected from DHT.')
self.dht_init()
2013-12-01 15:09:54 +00:00
checked = False
2022-10-23 22:11:12 +00:00
if not self.irc:
LOG.info('Disconnected from IRC.')
self.irc_init()
if not self.irc:
sleep(10)
continue
LOG.info('Waiting on IRC.')
readable, _, _ = select.select([self.irc], [], [], 0.1)
if not readable:
LOG.info('Waited on IRC but nothing to read.')
else:
2013-12-01 15:09:54 +00:00
self.readbuffer += self.irc.recv(4096)
2022-10-23 22:11:12 +00:00
lines = self.readbuffer.split(b'\n')
self.irc_check(lines)
LOG.info(f'Waited on IRC and got {len(lines)} lines.')
2013-12-01 15:09:54 +00:00
self.readbuffer = lines.pop()
for line in lines:
2022-10-23 22:11:12 +00:00
line = str(line, 'UTF-8')
i = line.find(' ')
print(line[i+1:])
l = line.rstrip().split()
2013-12-01 15:09:54 +00:00
rx = re.match(r':(.*?)!.*? PRIVMSG %s :(.*?)\r' %
2022-10-23 22:11:12 +00:00
self._sChannel, line, re.S)
2013-12-01 15:09:54 +00:00
if rx:
print('IRC> %s: %s' % rx.groups())
2014-02-20 09:01:45 +00:00
msg = '[%s]: %s' % rx.groups()
2013-12-22 16:33:15 +00:00
content = rx.group(2)
if content[1:].startswith('ACTION '):
2014-02-20 09:01:45 +00:00
action = '[%s]: %s' % (rx.group(1),
2013-12-22 16:33:15 +00:00
rx.group(2)[8:-1])
self.ensure_exe(self.group_action_send,
2022-10-23 22:11:12 +00:00
self.tox_group_id, action)
2013-12-11 15:55:40 +00:00
elif self.tox_group_id != None:
self.ensure_exe(self.group_message_send,
2022-10-23 22:11:12 +00:00
self.tox_group_id, msg)
2013-12-01 15:09:54 +00:00
if content.startswith('^'):
self.handle_command(content)
2022-10-23 22:11:12 +00:00
elif l[0] == 'PING':
2014-08-15 15:10:31 +00:00
self.irc_send('PONG %s\r\n' % l[1])
2022-10-23 22:11:12 +00:00
elif l[1] == '376':
# :End of /MOTD command
self.irc.send(bytes('PRIVMSG NickServ :IDENTIFY %s %s\r\n'
% (NICK, PWD,), 'UTF-8'))
self.irc.send(bytes('JOIN %s\r\n' % self._sChannel, 'UTF-8'))
elif l[1] == '421':
# 421 SyniTox .PRIVMSG :Unknown command
pass
elif l[1] == '477':
#477 SyniTox #tor :Cannot join channel (Need to be identified and verified to join this channel, '/msg NickServ help' to learn how to register and verify.)
self.irc.send(bytes('HELP \r\n', 'UTF-8'))
self.irc.send(bytes('MSG NickServ help\r\n', 'UTF-8'))
pass
2013-12-01 15:24:33 +00:00
2013-12-01 15:09:54 +00:00
self.do()
except KeyboardInterrupt:
2022-10-23 22:11:12 +00:00
ret = 0
except Exception as e:
LOG.exception(f'Error running program:\n{e}', exc_info=True)
ret = 1
else:
ret = 0
self.quit()
return ret
def quit(self):
self.del_callbacks()
self.save_to_file()
def save_to_file(self):
pass
2013-12-01 15:09:54 +00:00
def irc_send(self, msg):
success = False
while not success:
try:
2022-10-23 22:11:12 +00:00
self.irc.send(bytes(msg, 'UTF-8'))
success = True
break
except socket.error:
self.irc_init()
sleep(1)
2013-12-11 15:55:40 +00:00
def on_connection_status(self, friendId, status):
2013-12-11 16:02:01 +00:00
if not self.request and not self.joined \
and friendId == self.bid and status:
2022-10-23 22:11:12 +00:00
LOG.info('Groupbot online, trying to join group chat.')
2013-12-11 16:02:01 +00:00
self.request = True
2022-10-23 22:11:12 +00:00
self.ensure_exe(self.send_message, self.bid, 'invite')
2022-10-23 22:11:12 +00:00
def on_group_invite(self, friendid, invite_data, user_data):
2013-12-01 15:09:54 +00:00
if not self.joined:
self.joined = True
2014-12-17 11:15:36 +00:00
self.tox_group_id = self.join_groupchat(friendid, data)
2022-10-23 22:11:12 +00:00
LOG.info('Joined groupchat.')
2013-12-01 15:09:54 +00:00
2022-10-23 22:11:12 +00:00
def on_group_message(self, groupnumber, peer_id, message):
name = self.group_peername(groupnumber, peer_id)
2014-04-06 00:12:34 +00:00
if len(name) and name != NAME:
2013-12-01 15:09:54 +00:00
print('TOX> %s: %s' % (name, message))
2014-02-20 18:28:35 +00:00
if message.startswith('>'):
2014-02-20 18:34:59 +00:00
message = '\x0309%s\x03' % message
2014-03-13 19:31:26 +00:00
2022-10-23 22:11:12 +00:00
self.irc_send(b'PRIVMSG %s :[%s]: %s\r\n' %
(self._sChannel, name, message))
if message.startswith('^'):
2014-02-20 11:04:54 +00:00
self.handle_command(message)
2013-12-01 15:09:54 +00:00
2022-10-23 22:11:12 +00:00
def on_group_action(self, groupnumber, peer_id, action):
"""old? message type action?"""
name = self.group_peername(groupnumber, peer_id)
2014-04-06 00:12:34 +00:00
if len(name) and name != NAME:
2013-12-22 16:33:15 +00:00
print('TOX> %s: %s' % (name, action))
2014-02-20 18:28:35 +00:00
if action.startswith('>'):
2014-02-20 18:34:59 +00:00
action = '\x0309%s\x03' % action
2014-02-20 09:01:45 +00:00
self.irc_send('PRIVMSG %s :\x01ACTION [%s]: %s\x01\r\n' %
2022-10-23 22:11:12 +00:00
(self._sChannel, name, action))
2013-12-22 16:33:15 +00:00
def on_friend_request(self, pk, message):
2022-10-23 22:11:12 +00:00
LOG.info('Friend request from %s: %s' % (pk, message))
self.add_friend_norequest(pk)
2022-10-23 22:11:12 +00:00
LOG.info('Accepted.')
def on_friend_message(self, friendid, message):
if message == 'invite':
2014-03-13 19:33:34 +00:00
if not self.tox_group_id is None:
2022-10-23 22:11:12 +00:00
LOG.info('Inviting %s' % self.get_name(friendid))
2014-03-13 19:33:34 +00:00
self.invite_friend(friendid, self.tox_group_id)
return
else:
message = 'Waiting for GroupBot, please try again in 1 min.'
2022-10-23 22:11:12 +00:00
self.ensure_exe(self.send_message, friendid, message)
2014-02-20 11:27:49 +00:00
def send_both(self, content):
2022-10-23 22:11:12 +00:00
self.ensure_exe(self.group_message_send, self.tox_group_id, content)
self.irc_send('PRIVMSG %s :%s\r\n' % (self._sChannel, content))
2014-02-20 11:27:49 +00:00
2014-02-20 11:02:07 +00:00
def handle_command(self, cmd):
2014-02-20 11:27:49 +00:00
cmd = cmd[1:]
if cmd in ['syncbot', 'echobot']:
self.send_both(self.get_address())
2014-03-13 19:33:34 +00:00
elif cmd == 'resync':
sys.exit(0)
2014-02-20 11:27:49 +00:00
elif cmd.startswith('remember '):
args = cmd[9:].split(' ')
subject = args[0]
desc = ' '.join(args[1:])
self.memory[subject] = desc
2022-10-23 22:11:12 +00:00
if self.sMEMORY_DB:
with open(self.sMEMORY_DB, 'w') as f:
pickle.dump(self.memory, f)
2014-02-20 11:27:49 +00:00
self.send_both('Remembering ^%s: %s' % (subject, desc))
elif self.memory.has_key(cmd):
self.send_both(self.memory[cmd])
2014-02-20 11:02:07 +00:00
2022-10-23 22:11:12 +00:00
def iMain(oArgs):
assert oTOX_OPTIONS
assert oTOX_OARGS
sChannel = oArgs.irc_chan
sIRC_HOST = oArgs.irc_host
iIRC_PORT = oArgs.irc_port
o = SyniTox(oTOX_OPTIONS, sChannel, sIRC_HOST, iIRC_PORT)
o.start()
ret = o.iLoop()
return ret
def oToxygenToxOptions(oArgs):
data = None
tox_options = wrapper.tox.Tox.options_new()
if oArgs.proxy_type:
tox_options.contents.proxy_type = int(oArgs.proxy_type)
tox_options.contents.proxy_host = bytes(oArgs.proxy_host, 'UTF-8')
tox_options.contents.proxy_port = int(oArgs.proxy_port)
tox_options.contents.udp_enabled = False
else:
tox_options.contents.udp_enabled = oArgs.udp_enabled
if not os.path.exists('/proc/sys/net/ipv6'):
oArgs.ipv6_enabled = False
tox_options.contents.tcp_port = int(oArgs.tcp_port)
# overrides
tox_options.contents.local_discovery_enabled = False
tox_options.contents.dht_announcements_enabled = True
tox_options.contents.hole_punching_enabled = False
tox_options.contents.experimental_thread_safety = False
# REQUIRED!!
if oArgs.ipv6_enabled and not os.path.exists('/proc/sys/net/ipv6'):
LOG.warn('Disabling IPV6 because /proc/sys/net/ipv6 does not exist' + repr(oArgs.ipv6_enabled))
tox_options.contents.ipv6_enabled = False
else:
tox_options.contents.ipv6_enabled = bool(oArgs.ipv6_enabled)
if data: # load existing profile
tox_options.contents.savedata_type = enums.TOX_SAVEDATA_TYPE['TOX_SAVE']
tox_options.contents.savedata_data = c_char_p(data)
tox_options.contents.savedata_length = len(data)
else: # create new profile
tox_options.contents.savedata_type = enums.TOX_SAVEDATA_TYPE['NONE']
tox_options.contents.savedata_data = None
tox_options.contents.savedata_length = 0
#? tox_options.contents.log_callback = LOG
if tox_options._options_pointer:
# LOG.debug("Adding logging to tox_options._options_pointer ")
ts.vAddLoggerCallback(tox_options, ts.on_log)
else:
LOG.warn("No tox_options._options_pointer " +repr(tox_options._options_pointer))
return tox_options
def oArgparse(lArgv):
parser = ts.oMainArgparser()
parser.add_argument('profile', type=str, nargs='?', default=None,
help='Path to Tox profile')
# irc.libera.net #tox will not work over Tor
parser.add_argument('--irc_host', type=str, default='irc.oftc.net')
parser.add_argument('--irc_port', type=int, default=6667)
parser.add_argument('--irc_chan', type=str, default='#tor')
oArgs = parser.parse_args(lArgv)
for key in ts.lBOOLEANS:
if key not in oArgs: continue
val = getattr(oArgs, key)
setattr(oArgs, key, bool(val))
if hasattr(oArgs, 'sleep'):
if oArgs.sleep == 'qt':
pass # broken or gevent.sleep(idle_period)
elif oArgs.sleep == 'gevent':
pass # broken or gevent.sleep(idle_period)
else:
oArgs.sleep = 'time'
return oArgs
def main(lArgs=None):
global oTOX_OARGS
if lArgs is None: lArgs = []
oArgs = oArgparse(lArgs)
oTOX_OARGS = oArgs
global oTOX_OPTIONS
oTOX_OPTIONS = oToxygenToxOptions(oArgs)
ts.vSetupLogging(oArgs)
# ts.setup_logging(oArgs)
return iMain(oArgs)
if __name__ == '__main__':
sys.exit(main(sys.argv[1:]))
# Ran 34 tests in 86.589s OK (skipped=12)