def __init__(self, raw): """ Create a command representation by parsing a raw received message. Similar to Command, but prefix is a string, and command is an int. @param raw The full message in string form. """ # Ignoret the CRLF parts = raw[:-2].split() pre = None if Message.has_prefix(raw): # A reply source is just the server name pre = parts[0][1:] del parts[0] if len(parts) == 0: raise ValueError('message has no command') # A reply command is just a 3-digit code cmd = int(parts[0]) arg = ' '.join(parts[1:]) Message.__init__(self, pre, cmd, Message.parse_arguments(arg))
def __init__(self, request, client_address, server): self.keep_alive = True self.handshake_done = False self.is_master = False # 是否是控制机 self.is_client = True # 是否是用户机 self.xid = None # 绑定的编号 self.pwd = None # 绑定的密码 self.master_xid = None # 控制机的编号 self.master_pwd = None # 控制机的密码 self.json_type = True # 默认以JSON类型传输数据,False: 接收到的数据不能解析为json数据了。 self.last_send_message = None # 上次发送的数据 self.selector = selectors.DefaultSelector() self.selector.register(request, selectors.EVENT_READ) self.server = server # type: WebSocketServer self.message = Message() self.queue = queue.Queue() # 默认队列 self.request = request self.master_request = None # type: socket.socket self.master_handler = None # type: WebSocketServerRequestHandler self.client_requests = [] # 所有用户机的socket super().__init__(request, client_address, server)
def privmsg(serv, usr, n, m, *_): try: chan = serv.get_channel(n) us = serv.get_channel_users(chan) targets = us[:] targets.remove(usr) for t in targets: t.send(Message(usr.hostmask, Command.PRIVMSG, [n, m])) except BadChannelError: try: target = serv.get_user(n) target.send(Message(usr.hostmask, Command.PRIVMSG, [n, m])) except NoUserError: usr.send( Message(serv.hostname, Reply.ERR.NOSUCHNICK, [n, 'no such nick'])) except NoChannelError: usr.send( Message(serv.hostname, Reply.ERR.NOSUCHCHANNEL, [n, 'no such channel'])) except ValueError: usr.send( Message(serv.hostname, Reply.ERR.CANNOTSENDTOCHAN, [n, 'cannot send to channel']))
def __init__(self, raw): """ Create a command representation by parsing a raw received message. Use functionality from Message, then create a Hostmask from the prefix. @param raw The full message in string form. """ # Ignore the CRLF parts = raw[:-2].split() pre = None if Message.has_prefix(raw): # Create a hostmask from the prefix, ignoring the ':' at the start pre = Hostmask.from_raw(parts[0][1:]) del parts[0] if len(parts) == 0: raise ValueError('message has no command') cmd = parts[0] # Every 'part' after the command is an argument arg = ' '.join(parts[1:]) Message.__init__(self, pre, cmd, Message.parse_arguments(arg))
def setup(serino): chrome = Chrome(serino, "Chrome") message = Message(serino, "Message") email = Email(serino, "Email") call = Telephony(serino, "call") # chrome.setup() message.setup() email.setup("*****@*****.**", "Password001", "exchange") call.setup_contacts()
def setup(serino): chrome = Chrome(serino,"Chrome") message = Message(serino,"Message") email = Email(serino,"Email") call = Telephony(serino,"call") # chrome.setup() message.setup() email.setup("*****@*****.**", "Password001", "exchange") call.setup_contacts()
def check_state(serv, usr, state, *_): if state == True and not usr.is_registered(): usr.send( Message(serv.hostname, Reply.ERR.NOTREGISTERED, ['you have not registered'])) return False elif state == False and usr.is_registered(): usr.send( Message(serv.hostname, Reply.ERR.ALREADYREGISTERED, ['unauthorized command (already registered)'])) return False else: return True
def _message(self, buddy, message, **options): '@return: True if the message was allowed' # Always use local time for online messages, in case user's clock is wrong. if not options.get('offline', True): options.pop('timestamp', None) if options.get('offline', False): self.autoresponded = True # Prevent autoresponse to offline messages # if timestamp is None substitute it with UTC now timestamp = options.pop('timestamp', None) if timestamp is None: timestamp = datetime.utcnow() from common.message import Message messageobj = Message(buddy=buddy, message=message, timestamp=timestamp, conversation=self, **options) from plugin_manager import plugin_hub plugin_hub.act('digsby.im.msg.async', self, messageobj, options.get('type', None)) from common import profile return profile.on_message(messageobj) is not profile.on_message.VETO
def buddy_says(self, buddy, message, **options): '@return: True if the message was allowed' if not isinstance(message, unicode): raise TypeError, 'buddy_says needs unicode got type %r: %r' % ( type(message), message) try: timestamp = options.get('timestamp', None) if timestamp is None: timestamp = datetime.utcnow() content_type = options.pop('content_type', 'text/plain') from common.message import Message messageobj = Message(buddy=buddy, message=message, timestamp=timestamp, content_type=content_type) from plugin_manager import plugin_hub msgtype = options.get('type', None) # Allow plugins to make changes to the messageobj plugin_hub.act('digsby.im.msg.pre', messageobj, msgtype) if messageobj.message != '': # TODO: pass entire (potentially) changed messageobj to self._message return self._message(buddy, messageobj.message, content_type=messageobj.content_type, **options) except Exception, e: log.error("Failed to parse message %r", e) # do what it used to do return self._message(buddy, message, **options)
def user(serv, usr, n, h, s, r, *_): usr.update(username=n) if usr.can_register(): usr.register() usr.send( Message(serv.hostname, Reply.RPL.WELCOME, ['welcome to pylay IRC ' + format(usr.hostmask)]))
def on_success(): self.show_message( Message(buddy=frm.self_buddy, message=message[:SMS_MAX_LENGTH], conversation=self.convo, type='outgoing')) self.ClearAndFocus()
def test_write_read_unicode(self): with self.scratch_logger() as logger: unicode_msg = u'\xd0\xb9\xd1\x86\xd1\x83\xd0\xba\xd0\xb5' # log a message with unicode msg = Message(buddy=self.buddy, message=unicode_msg, type='incoming', conversation=self.convo, timestamp=datetime(month=12, day=25, year=2000, hour=12)) logger.on_message(msg) # check that the file is on disk logfile = os.path.join( logger.OutputDir, r'aim\digsby03\digsby01_aim\2000-12-25.html') self.assert_(os.path.isfile(logfile), logfile) history = logger.history_for(self.account, self.buddy) # assert that unicode was encoded and decoded properly logmsg = list(history)[0] self.assert_(logmsg.message == unicode_msg)
def parse_html_slow(html): 'Uses Beautiful Soup to parse messages out of a log file.' html = html.decode('utf-8', 'ignore') soup = soupify(html, markupMassage=((br_re, lambda m: '<br />'), )) messages = [] strptime = datetime.strptime for div in soup.findAll(message_divs): try: buddyname = div.findAll('span', class_buddy)[0].renderContents(None) timestamp = parse_timestamp(div['timestamp']) message = div.findAll('span', class_msgcontent)[0].renderContents(None) type = div['class'].replace('message', '').strip() auto = boolify(div.get('auto', 'false')) except Exception: print_exc() else: messages.append( Message(buddy=S(name=buddyname), timestamp=timestamp, message=message, type=type, auto=auto)) log_info('parse_html_slow with %d bytes returning %d messages', len(html), len(messages)) return messages
def on_message(self, message): """ raw websocket message handler. Message should be in json formatted dictionary with the following keys:: id - unique message id set by client. Response will be sent with the sama id route - messaeg route. Refers message handler that will be used body - message body that will be routed to handler. :param : raw message in json format """ json_message = json.loads(message) message = Message.from_json(json_message=json_message, handler=self) msg_handlers = self._app.msg_handler_registry.match(message.get_route()) ioloop = IOLoop.current() for msg_handler_cls in msg_handlers: msg_handler = msg_handler_cls() future = msg_handler.call(message=message) def callback(future): msg_handler.result(future) if future.done(): pass else: ioloop.add_future(future, callback)
def test_html_entities(self): with self.scratch_logger() as logger: message = u'foo bar <b>meep</b>'.encode('xml') msg = Message(buddy=self.buddy, message=message, type='incoming', conversation=self.convo, timestamp=datetime(month=12, day=25, year=2000, hour=12)) logger.on_message(msg) # check that the file is on disk logfile = os.path.join( logger.OutputDir, r'aim\digsby03\digsby01_aim\2000-12-25.html') self.assert_(os.path.isfile(logfile), logfile) print open(logfile, 'rb').read() history = list(logger.history_for(self.account, self.buddy)) self.assert_equal(1, len(history)) self.assert_('<' not in history[0].message)
def setUpClass(cls): serino = "MDEVICE" serino = "a541c694" if len(sys.argv)>1: serino = sys.argv[1] cls.mod = Message(serino, "Message") cls.set = Settings(cls.mod.device, "Settings")
def join(serv, usr, n, *_): try: chan = serv.get_channel(n, True) serv.join_channel(chan, usr) us = serv.get_channel_users(chan) targets = us[:] targets.remove(usr) for t in targets: t.send(Message(usr.hostmask, Command.JOIN, [n])) except BadChannelError: usr.send( Message(serv.hostname, Reply.ERR.NOSUCHCHANNEL, [n, 'no such channel']))
def part(serv, usr, n, *_): try: chan = serv.get_channel(n) serv.part_channel(chan, usr) targets = serv.get_channel_users(chan) for t in targets: t.send(Message(usr.hostmask, Command.PART, [n])) except (BadChannelError, NoChannelError): usr.send( Message(serv.hostname, Reply.ERR.NOSUCHCHANNEL, [n, 'no such channel'])) except NotInChannelError: usr.send( Message(serv.hostname, Reply.ERR.NOTONCHANNEL, [n, 'you\'re not on that channel']))
def nick(serv, usr, n, *_): try: serv.get_user(n) usr.send( Message(serv.hostname, Reply.ERR.NICKNAMEINUSE, [n, 'nickname is already in use'])) except NoUserError: try: usr.update(nickname=n) if usr.can_register(): usr.register() usr.send( Message(serv.hostname, Reply.RPL.WELCOME, ['welcome to pylay IRC ' + format(usr.hostmask)])) except BadNicknameError: usr.send( Message(serv.hostname, Reply.ERR.ERRONEUSNICKNAME, [n, 'erroneous nickname']))
def quit(serv, usr, m=None, *_): hm = usr.hostmask if not hm.is_valid(): return us = (u for u in serv.users if u != usr) for u in us: u.send(Message(hm, Command.QUIT, [m if m else hm.nickname])) serv.remove_user(usr)
def __init__(self, device, mod): self.device = connect_device(device) self.logger = createlogger(mod) self.log_path = create_folder() self.camera = Camera(self.device, "task_camera") self.product = Configs("common").get("product", "Info") if self.product == "Sprints": from common.chrome import Chrome self.browser = Chrome(self.device, "task_browser") else: self.browser = Browser(self.device, "Browser") self.tel = Telephony(self.device, "task_tel") self.message = Message(self.device, "task_message") self.settings = Settings(self.device, "switch_nw") self.suc_times = 0 self.mod_cfg = GetConfigs(mod) self.test_times = 0 self.dicttesttimes = self.mod_cfg.get_test_times() for test_time in self.dicttesttimes: self.test_times += int(self.dicttesttimes[test_time]) self.test_times = self.test_times * 2 + 4 self.logger.info("Trace Total Times " + str(self.test_times))
def __init__(self,device,mod): self.device = connect_device(device) self.logger = createlogger(mod) self.log_path = create_folder() self.camera = Camera(self.device,"task_camera") self.product = Configs("common").get("product","Info") if self.product == "Sprints": from common.chrome import Chrome self.browser = Chrome(self.device,"task_browser") else: self.browser = Browser(self.device,"Browser") self.tel = Telephony(self.device,"task_tel") self.message = Message(self.device,"task_message") self.settings = Settings(self.device,"switch_nw") self.suc_times = 0 self.mod_cfg = GetConfigs(mod) self.test_times = 0 self.dicttesttimes = self.mod_cfg.get_test_times() for test_time in self.dicttesttimes: self.test_times += int(self.dicttesttimes[test_time]) self.test_times = self.test_times*2 + 4 self.logger.info("Trace Total Times " + str(self.test_times))
def parse_html_lxml(html): 'parses a logfile with lxml' messages = [] doc = lxml.html.document_fromstring(html, parser=lxmlparser()) for div in doc.xpath('//html/body/div'): try: message_type = div.attrib.get('class', '') if not 'message' in message_type: continue message_type = message_type.replace('message', '').strip() if not message_type in ('incoming', 'outgoing'): continue buddyname = div.find_class('buddy')[0].text timestamp = div.attrib.get('timestamp') if timestamp is not None: timestamp = parse_timestamp(timestamp) message = render_contents(div.find_class('msgcontent')[0]) auto = boolify(div.attrib.get('auto', 'false')) except Exception: print_exc() else: messages.append( Message( buddy=S(name=buddyname), timestamp=timestamp, message=message, type=message_type, auto=auto, has_autotext=auto, )) return messages
def test_str(self): payload = 'some payload' message = Message(payload) self.assertIn(payload, str(message))
def test_payload(self): obj = object() message = Message(obj) self.assertIs(obj, message.payload)
class MultiTask(Common): def __init__(self, device, mod): self.device = connect_device(device) self.logger = createlogger(mod) self.log_path = create_folder() self.camera = Camera(self.device, "task_camera") self.product = Configs("common").get("product", "Info") if self.product == "Sprints": from common.chrome import Chrome self.browser = Chrome(self.device, "task_browser") else: self.browser = Browser(self.device, "Browser") self.tel = Telephony(self.device, "task_tel") self.message = Message(self.device, "task_message") self.settings = Settings(self.device, "switch_nw") self.suc_times = 0 self.mod_cfg = GetConfigs(mod) self.test_times = 0 self.dicttesttimes = self.mod_cfg.get_test_times() for test_time in self.dicttesttimes: self.test_times += int(self.dicttesttimes[test_time]) self.test_times = self.test_times * 2 + 4 self.logger.info("Trace Total Times " + str(self.test_times)) def remove(self): self.logger.debug("remove all opened activities") self.device.press.menu() if self.device(description="Clear all").wait.exists(timeout=2000): self.device(description="Clear all").click() self.device.delay(5) return True return False def start(self): self.logger.debug("Start Some activities") self.logger.debug("Launch Contacts") #self.tel.start_app("Contacts") self.tel.enter_contacts() self.device.delay(3) self.logger.debug("Launch Message") self.message.start_app("Messaging") self.device.delay(3) self.logger.debug("Launch Dialer") #self.tel.start_app("Call") self.tel.enter_dialer() self.device.delay(3) self.logger.debug("Launch Camera") self.camera.start_app("Camera") self.device.delay(3) self.logger.debug("Launch Browser") #self.browser.start_app("Browser") self.browser.enter() def make_call(self, number): if self.tel.enter_dialer(): try: if self.tel.call_from_dialer(number): self.suc_times += 1 self.logger.info("Trace Success Make Call") return True else: self.save_fail_img() return False except Exception, e: self.save_fail_img() # common.common.log_traceback(traceback.format_exc()) return False
def invalid_handler(serv, usr, cmd): usr.send( Message(serv.hostname, Reply.ERR.NEEDMOREPARAMS, [cmd, 'not enough parameters']))
class MultiTask(Common): def __init__(self,device,mod): self.device = connect_device(device) self.logger = createlogger(mod) self.log_path = create_folder() self.camera = Camera(self.device,"task_camera") self.product = Configs("common").get("product","Info") if self.product == "Sprints": from common.chrome import Chrome self.browser = Chrome(self.device,"task_browser") else: self.browser = Browser(self.device,"Browser") self.tel = Telephony(self.device,"task_tel") self.message = Message(self.device,"task_message") self.settings = Settings(self.device,"switch_nw") self.suc_times = 0 self.mod_cfg = GetConfigs(mod) self.test_times = 0 self.dicttesttimes = self.mod_cfg.get_test_times() for test_time in self.dicttesttimes: self.test_times += int(self.dicttesttimes[test_time]) self.test_times = self.test_times*2 + 4 self.logger.info("Trace Total Times " + str(self.test_times)) def remove(self): self.logger.debug("remove all opened activities") self.device.press.menu() if self.device(description= "Clear all").wait.exists(timeout = 2000): self.device(description= "Clear all").click() self.device.delay(5) return True return False def start(self): self.logger.debug("Start Some activities") self.logger.debug("Launch Contacts") #self.tel.start_app("Contacts") self.tel.enter_contacts() self.device.delay(3) self.logger.debug("Launch Message") self.message.start_app("Messaging") self.device.delay(3) self.logger.debug("Launch Dialer") #self.tel.start_app("Call") self.tel.enter_dialer() self.device.delay(3) self.logger.debug("Launch Camera") self.camera.start_app("Camera") self.device.delay(3) self.logger.debug("Launch Browser") #self.browser.start_app("Browser") self.browser.enter() def make_call(self,number): if self.tel.enter_dialer(): try: if self.tel.call_from_dialer(number): self.suc_times += 1 self.logger.info("Trace Success Make Call") return True else: self.save_fail_img() return False except Exception,e: self.save_fail_img() # common.common.log_traceback(traceback.format_exc()) return False
class WebSocketServerRequestHandler(socketserver.BaseRequestHandler): def __init__(self, request, client_address, server): self.keep_alive = True self.handshake_done = False self.is_master = False # 是否是控制机 self.is_client = True # 是否是用户机 self.xid = None # 绑定的编号 self.pwd = None # 绑定的密码 self.master_xid = None # 控制机的编号 self.master_pwd = None # 控制机的密码 self.json_type = True # 默认以JSON类型传输数据,False: 接收到的数据不能解析为json数据了。 self.last_send_message = None # 上次发送的数据 self.selector = selectors.DefaultSelector() self.selector.register(request, selectors.EVENT_READ) self.server = server # type: WebSocketServer self.message = Message() self.queue = queue.Queue() # 默认队列 self.request = request self.master_request = None # type: socket.socket self.master_handler = None # type: WebSocketServerRequestHandler self.client_requests = [] # 所有用户机的socket super().__init__(request, client_address, server) def reg_send(self): # print("reg_send.....{}".format(self.request.getpeername())) self.selector.modify(self.request, selectors.EVENT_WRITE) def reg_read(self): # print("reg_read.....{}".format(self.request.getpeername())) self.selector.modify(self.request, selectors.EVENT_READ) def handle(self): # print("handle.....{}".format(self.request.getpeername())) while self.keep_alive: # 获取图像数据 # print("selector.select>>>>>>{}".format(self.request.getpeername())) selection_keys = self.selector.select() for key, events in selection_keys: if key.fileobj == self.request: if events == selectors.EVENT_READ: # 客户端读事件 # print("read_message。。。。") self.read_message() elif events == selectors.EVENT_WRITE: # 客户端写事件 # print("send_message。。。。") self.send_message() def handshake(self, request_header): # 从请求的数据中获取 Sec-WebSocket-Key, Upgrade sock = self.request # type: socket.socket request, payload = request_header.split("\r\n", 1) maps = Properties(separator=':', ignore_case=True).load(payload) # type: dict # try: self.handshake_done = handshake(self.request, maps) if self.handshake_done > 0: self.server.new_client(self) ip = get_real_ip(maps) if not ip or ip == "unknown": ip = sock.getpeername()[0] print('handshake success...', ip) else: self.keep_alive = False # except ValueError as ve: # print("handshake.ve", ve) def read_message(self): """ 读取客户端的信息 :return: """ try: # 客户端 message = self.request.recv(socket_buffer_size) if not message: print('read_message: client disconnect. received empty data!') self.keep_alive = False return if self.handshake_done is False: try: request_header = str(message, encoding='ascii') except UnicodeDecodeError as e: print("read_message.UnicodeDecodeError:", e) self.keep_alive = False return self.handshake(request_header) else: # 如果是用户机的话,就通过解包的来获取相关的操作信息 self.message.reset_pos() # 解析文本 # 在读下一个字符,看看有没有客户端两次传入,一次解析的。 # 考虑两份数据一次接收的问题。需要先看一下第一个字符是否有效。 while self.message.read_bytes(message, 1): self.message.backward_pos() try: # 1,控制机只负责上传图片数据,接收JSON数据 # 2,用户机只负责上传JSON数据,接收图片数据 # 当没有确定是什么类型的机器,默认都是通过JSON类型上传/接收数据。 opcode, decoded = self.message.unpack_message(message) if opcode == 0x01: # 文本 user_data = json.loads( str(decoded, encoding="utf-8")) # type: dict self.handle_client_message(user_data) elif opcode == 0x02: # 二进制 if self.is_master: # 控制机器 # 接收到了图像数据,将图像发送给用户机 # 发送数据给用户机 if len(self.client_requests) > 0: # encode_message = pack_message(decoded, OPCODE_BINARY) # print("encode_message:", encode_message) self.client_send_message( pack_message(decoded, OPCODE_BINARY)) # 响应数据给控制机,告诉控制机,我已经将数据发送给对方了。 reply_message = { "size": { "width": 0, "height": 0 }, "action": "capture", "emit": "change" } else: reply_message = { "size": { "width": 0, "height": 0 }, "action": "pause" } self.queue.put( json.dumps(reply_message).encode(), block=False) self.reg_send() except ValueError as e: print(e) self.keep_alive = False # print('read next....') except (ConnectionAbortedError, ConnectionResetError, TimeoutError) as es: # [Errno 54] Connec tion reset by peer # self.shutdown_request() print(es) self.finish() def handle_client_message(self, user_data: dict): """ 处理用户机的消息 :param user_data: 用户机提交过来的信息 :return: """ print("收到用户信息:", user_data) if "xid" in user_data: # 客户端上传xid信息 self.xid = user_data.get("xid", None) self.server.new_client(self) if "pwd" in user_data: # 客户端上传密码 self.pwd = user_data.get("pwd", None) if "master" in user_data: master = user_data.get("master", None) # type: dict if master: self.master_xid = master.get("xid", None) self.master_pwd = master.get("pwd", None) # 可以进行校验密码 # 密码校验成功 # 可以开始连通目标机器 handler = self.server.get_client( self.master_xid) # type: WebSocketServerRequestHandler if handler and handler.request: print("找到目标机器..") handler.is_master = True # 设置为控制机 handler.is_client = False # 当前机器不能作为客户端,意思是不能连接到其他机器 handler.json_type = False # 接收到的数据不能解析为json数据了。 self.master_request = handler.request # type: socket.socket self.master_handler = handler # 如果关闭的socket没有在client_requests中移除的话,那么就会一直在收。 print("handler.client_requests: ", handler.client_requests) if len(handler.client_requests) > 0: # 已经有请求存在,说明已经有在交互了,无需再次重复发送给控制机。 handler.client_requests.append(self.request) else: handler.client_requests.append(self.request) print("准备发送向{}数据".format( self.master_request.getpeername())) # 发送数据给对方 # 请求数据 reply_message = { "size": { "width": 0, "height": 0 }, "action": "capture", "emit": "full" } # 将数据发送给控制机 print("将数据发送给控制机") self.master_send_message(json.dumps(reply_message)) else: print("无法找到目标机器!") if "key" in user_data and not self.is_master and self.is_client: # 客户端传过来的按键 pass if "mouse" in user_data and not self.is_master and self.is_client: # 客户端传过来的鼠标位置 pass def master_send_message(self, data: str): """ 发送消息给控制机 :param data: :return: """ try: payload = pack_message(data) self.master_request.sendall(payload) except BrokenPipeError as bpe: print("master_send_message.BrokenPipeError:", bpe) def client_send_message(self, payload: bytes): """ 发送数据给所有用户机 :param payload: 控制机传过来的二进制数据 :return: """ # output: bytearray = self.message.unpack_message(data) # print("requests:", self.client_requests) for request in self.client_requests: try: request.sendall(payload) except OSError as ose: self.client_requests.remove(request) print("OSError:(client_request.sendall)", ose) def send_message(self): """ 发送消息给用户机 :return: """ message = b'' while not self.queue.empty(): message += self.queue.get_nowait() presentation = decode_utf8(message, flag='replace', replace_str='?') payload = pack_message(presentation) try: # print("发送数据", self.request) self.request.send(payload) self.reg_read() except BrokenPipeError as bpe: print("bpe:", bpe) def send_raw_message(self, data: bytes): """ 发送裸数据给用户机 :param data: :return: """ try: self.request.send(data) self.reg_read() except BrokenPipeError as bpe: print("bpe:", bpe) def finish(self): if self.master_handler: if len(self.master_handler.client_requests) > 0: # 将自己从master中删除。 print("self.master_handler.client_requests", self.master_handler.client_requests) self.master_handler.client_requests.remove(self.request) print("关闭连接了", self.request) self.keep_alive = False
def test_payload(self): obj = object() message = Message(obj) self.assertIs(obj, message.payload())
def unknown_handler(serv, usr, cmd): usr.send( Message(serv.hostname, Reply.ERR.UNKNOWNCOMMAND, [cmd, 'unknown command']))