def create_slack_websocket(data): global ws web_socket_url = data['url'] try: ws = create_connection(web_socket_url) ws.sock.setblocking(0) w.hook_fd(ws.sock._sock.fileno(), 1, 0, 0, "slack_cb", "") except socket.error: return False return True
def init_socket(): global sock kill_daemon() if sock is None: sock_path = '%s/signal.sock' % weechat.info_get("weechat_dir", "") try: os.unlink(sock_path) except OSError: if os.path.exists(sock_path): raise sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) sock.bind(sock_path) sock.listen(5) weechat.hook_fd(sock.fileno(), 1, 1, 0, 'receive', '')
def weecat_command_cb(data, buffer, args): global weecat_buffers, cmds_by_buffer, listen_hooks try: this_file = open(args) except IOError as e: weechat.prnt("", weechat.prefix("error") + "weecat: " + e.strerror) return weechat.WEECHAT_RC_ERROR filename = this_file.name if not args in listen_hooks: new_buffer = weechat.buffer_new( "wc: " + filename, "weecat_input_cb", "", "weecat_close_cb", "" ) weechat.buffer_set(new_buffer, "title", "weecat: " + filename) weechat.hook_signal_send("logger_backlog", weechat.WEECHAT_HOOK_SIGNAL_POINTER, new_buffer) listen_hooks[filename] = weechat.hook_fd(this_file.fileno(), 1, 0, 0, "weecat_update_cb", new_buffer) weechat.buffer_set(new_buffer, "display", "1") # switch to it weecat_buffers.add(new_buffer) files_by_buffer[new_buffer] = this_file return weechat.WEECHAT_RC_OK
def connect(self): self.create_buffer() self.disconnect() weechat.prnt( self.buffer, 'Connecting to %s:%s' % (self.get_option('host'), self.get_option('port'))) try: hints = socket.getaddrinfo(self.get_option('host'), self.get_option('port'), socket.AF_UNSPEC, socket.SOCK_STREAM, 0, socket.AI_PASSIVE) except socket.error as e: weechat.prnt(self.buffer, '%s%s' % (weechat.prefix('error'), e.args[1])) else: for res in hints: af, socktype, proto, canonname, sa = res try: self.socket = socket.socket(af, socktype, proto) self.socket.connect(sa) except socket.error: self.socket = None continue break if self.socket is None: weechat.prnt(self.buffer, '%sCould not connect' % (weechat.prefix('error'), )) else: self.hook_fd = weechat.hook_fd(self.socket.fileno(), 1, 0, 0, 'wee_ns_hook_fd_cb', '')
def urlserver_server_start(): """Start mini HTTP server.""" global urlserver, urlserver_settings if urlserver['socket']: weechat.prnt('', 'URL server already running') return port = 0 try: port = int(urlserver_settings['http_port']) except: port = 0 urlserver['socket'] = socket.socket(socket.AF_INET, socket.SOCK_STREAM) urlserver['socket'].setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) try: urlserver['socket'].bind((urlserver_settings['http_hostname'] or socket.getfqdn(), port)) except Exception as e: weechat.prnt('', '%sBind error: %s' % (weechat.prefix('error'), e)) urlserver['socket'] = None urlserver_server_status() return urlserver['socket'].listen(5) urlserver['hook_fd'] = weechat.hook_fd(urlserver['socket'].fileno(), 1, 0, 0, 'urlserver_server_fd_cb', '') urlserver_server_status()
def run(self): self.pid, fd = self.fork() self.hook_fd = weechat.hook_fd(fd, 1, 0, 0, "term_fd_cb", self.buffer) self.f = os.fdopen(fd, "w+b", 0) weechat.buffer_set(self.buffer, "display", "1") # switch to buffer
def connect(self): self.create_buffer() self.disconnect() weechat.prnt(self.buffer, 'Connecting to %s:%s' % (self.get_option('host'), self.get_option('port'))) try: hints = socket.getaddrinfo(self.get_option('host'), self.get_option('port'), socket.AF_UNSPEC, socket.SOCK_STREAM, 0, socket.AI_PASSIVE) except socket.error as e: weechat.prnt(self.buffer, '%s%s' % (weechat.prefix('error'), e.args[1])) else: for res in hints: af, socktype, proto, canonname, sa = res try: self.socket = socket.socket(af, socktype, proto) self.socket.connect(sa) except socket.error: self.socket = None continue break if self.socket is None: weechat.prnt(self.buffer, '%sCould not connect' % (weechat.prefix('error'),)) else: self.hook_fd = weechat.hook_fd(self.socket.fileno(), 1, 0, 0, 'wee_ns_hook_fd_cb', '')
def create_slack_websocket(self, data): web_socket_url = data['url'] try: self.ws = create_connection(web_socket_url) self.ws.sock.setblocking(0) self.ws_hook = w.hook_fd(self.ws.sock._sock.fileno(), 1, 0, 0, "slack_websocket_cb", self.identifier) return True except: return False
def init_socket(): global signald_socket global signald_hook signald_socket = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) try: signald_socket.connect(options["socket"]) # weechat really wants the last argument to be a string, but we really # want it to be bytes. so we end up having to do a bunch of gnarly # decoding and stuff in receive(). c'est la vie. signald_hook = weechat.hook_fd(signald_socket.fileno(), 1, 0, 0, 'receive', '') except Exception: logger.exception("Failed to connect to signald socket")
def setup_udp_listener(self): for key in ['udp_listen_ip', 'udp_listen_port', 'udp_listen_pass']: if self.state[key] and self.state[key] == '': return dlog("UDP listener disabled: missing '%s' setting" % key) if self.udp_socket_open == True: self.udp_socket.close() self.udp_socket_open = False self.udp_socket = socket.socket(socket.AF_INET6, socket.SOCK_DGRAM) self.udp_socket.bind( (self.state['udp_listen_ip'], self.state['udp_listen_port'])) self.udp_socket_open = True hook = weechat.hook_fd(self.udp_socket.fileno(), 1, 0, 0, "shim_wcb_handle_udp_input", "") dlog("UDP listener started at [%s]:%s!" % (self.state['udp_listen_ip'], self.state['udp_listen_port']))
def create_stream(name, args = ""): global sock_fd_dict global proc_hooks global sock_hooks if proc_hooks.get(name): return "Stream has already been created, close it before trying to open a new one" #Check if buffer exists buffer = weechat.buffer_search("python", name) if buffer == "": buffer = weechat.buffer_new(name, "buffer_input_cb", name, "stream_close_cb", name) setup_buffer(buffer) if not sock_fd_dict.get(name): file_name = tempfile.gettempdir() + "/we_tw_" + name if os.path.exists(file_name): os.remove(file_name) server = socket.socket( socket.AF_UNIX, socket.SOCK_STREAM ) server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) server.bind(file_name) #Don't block, timeout if no data is present server.setblocking(0) server.listen(1) file_fd = server.fileno() sock_fd_dict[str(file_fd)] = name sock_fd_dict[name] = server sock_hooks[name] = weechat.hook_fd(file_fd, 1, 0, 0, "twitter_stream_cb", buffer) options = dict(screen_name = script_options['screen_name'], name = name, alt_rt_style = int(script_options['alt_rt_style']), home_replies = int(script_options['home_replies']), stream_args = args) proc_hooks[name] = weechat.hook_process("python3 " + SCRIPT_FILE_PATH + " " + script_options["oauth_token"] + " " + script_options["oauth_secret"] + " " + "stream " + file_name + ' "' + str(options) + '"', 0 , "my_process_cb", str([buffer,"Stream"])) return "Started stream"
def urlserver_server_start(): """Start mini HTTP server.""" global urlserver, urlserver_settings if urlserver["socket"]: weechat.prnt("", "URL server already running") return port = 0 try: port = int(urlserver_settings["http_port"]) except: port = 0 urlserver["socket"] = socket.socket(socket.AF_INET, socket.SOCK_STREAM) urlserver["socket"].setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) try: urlserver["socket"].bind((urlserver_settings["http_hostname"] or socket.getfqdn(), port)) except Exception as e: weechat.prnt("", "%sBind error: %s" % (weechat.prefix("error"), e)) urlserver["socket"] = None urlserver_server_status() return urlserver["socket"].listen(5) urlserver["hook_fd"] = weechat.hook_fd(urlserver["socket"].fileno(), 1, 0, 0, "urlserver_server_fd_cb", "") urlserver_server_status()
def buf_node_in(pssName, buf, args): global psses ctx = {} currentPss = None argv = "" argc = 0 bufname = "" # parse cmd input # \todo remove consecutive whitespace argv = args.split(" ") argc = len(argv) # first we handle commands that are node independent # the connect command is the same for any context if argv[0] == "connect": host = "127.0.0.1" port = "8546" pssName = "" if argc < 2: wOut(PSS_BUFPFX_ERROR, [], "!!!", "invalid command <TODO insert help text>") pssName = argv[1] if argc > 2: host = argv[2] if argc > 3: port = argv[3] if pssName in psses: existingBuf = weechat.buffer_search("python", "pss.node." + pssName) if existingBuf != "": wOut( PSS_BUFPFX_DEBUG, [], "", "pss " + pssName + " already exists, changing to that buffer") weechat.buffer_set(bufs[pssName], "display", "1") return weechat.WEECHAT_RC_OK if host == "": host = weechat.config_get_plugin(pssName + "_url", host) if port == "": port = weechat.config_get_plugin(pssName + "_port", port) wOut(PSS_BUFPFX_DEBUG, [], "", "pss " + pssName + " already exists") else: psses[pssName] = pss.Pss(pssName, host, port) wOut(PSS_BUFPFX_OK, [], "+++", "added pss " + pssName) # regardless of if we have the node already, store the connection parameters for later for this node name weechat.config_set_plugin(pssName + "_url", host) weechat.config_set_plugin(pssName + "_port", port) # if we made it here we don't have a buffer for this node already # so create it and merge the node buffer with core so we can do the neat ctrl-x trick bufs[pssName] = weechat.buffer_new("pss.node." + pssName, "buf_node_in", pssName, "buf_node_close", pssName) weechat.buffer_set(bufs[pssName], "short_name", "pss." + pssName) weechat.buffer_set(bufs[pssName], "title", "PSS '" + pssName + "' | not connected") weechat.buffer_merge(bufs[pssName], weechat.buffer_search_main()) weechat.buffer_set(bufs[pssName], "display", "1") # now that we have the buffer up we have somewhere to write output relevant to this connection # we can proceed with connection in the pss instance wOut(PSS_BUFPFX_WARN, [bufs[pssName]], "0-> 0", "connecting to '" + pssName + "'") if not psses[pssName].connect(): wOut( PSS_BUFPFX_ERROR, [bufs[pssName]], "0-x 0", "connect to '" + pssName + "' failed: " + psses[pssName].error()['description']) return weechat.WEECHAT_RC_ERROR wOut(PSS_BUFPFX_OK, [bufs[pssName]], "0---0", "connected to '" + pssName + "'") # \todo temporary solution, swarm gateway should be set explicitly or at least we need to be able to choose port hookSocks.append( weechat.hook_connect("", host, 8500, 0, 0, "", "sock_connect", pssName)) # start processing inputs on the websocket hookFds[pssName] = weechat.hook_fd(psses[pssName].get_fd(), 1, 0, 0, "msgPipeRead", pssName) hookTimers.append( weechat.hook_timer(feedBoxPeriod, 0, 0, "processFeedBox", pssName)) # set own nick for this node # \todo use configurable global default nick # \todo clean up messy pubkey slicing (should be binary format in pss obj) pubkey = psses[pssName].key[2:] selfs[pssName] = pss.PssContact( PSS_DEFAULT_NICK, psses[pssName].key, pss.publickey_to_account(pubkey.decode("hex")).encode("hex"), psses[pssName].key) wOut(PSS_BUFPFX_OK, [bufs[pssName]], pssName, "nick is " + selfs[pssName].nick) return weechat.WEECHAT_RC_OK # get the context we're getting the command in # if we are not in pss context, # the we assume that the first argument is the name of the node # /pss oc add someone key addr # becomes # /pss add someone key addr # and "oc" is set to pssName # \todo consider exception for connect-command ctx = buf_get_context(buf) wOut(PSS_BUFPFX_DEBUG, [], "", "ctx: " + repr(ctx['t']) + " n " + ctx['n'] + " h " + ctx['h']) shiftArg = False # t 0 means any non-pss buffer if ctx['t'] == 0 and argv[0] != "connect": pssName = argv[0] argv = argv[1:] argc -= 1 else: pssName = ctx['n'] wOut(PSS_BUFPFX_DEBUG, [], "!!!", "after ctx " + pssName) # see if we already have this node registered if not pssName in psses: wOut(PSS_BUFPFX_ERROR, [], "!!!", "unknown pss connection '" + pssName + "'") return weechat.WEECHAT_RC_ERROR currentPss = psses[pssName] # set configuation values if argv[0] == "set": if argc < 3: wOut(PSS_BUFPFX_ERROR, [], "!!!", "insufficient number of arguments <TODO help output") return weechat.WEECHAT_RC_ERROR k = argv[1] v = argv[2] # for now we handle privkeys directly # we will read keystore jsons in near future instead, though if k == "pk": try: privkey = pss.clean_privkey(v) except: wOut(PSS_BUFPFX_ERROR, [], "!!!", "invalid key format") return weechat.WEECHAT_RC_ERROR try: currentPss.set_account_write(privkey.decode("hex")) except ValueError as e: wOut(PSS_BUFPFX_ERROR, [], "!!!", "set account fail: " + str(e)) return weechat.WEECHAT_RC_ERROR else: wOut(PSS_BUFPFX_ERROR, [], "!!!", "unknown config key") return weechat.WEECHAT_RC_ERROR wOut(PSS_BUFPFX_DEBUG, [], "!!!", "set pk to " + v + " for " + pssName) weechat.WEECHAT_RC_OK # add a recipient to the address books of plugin and node # \todo currently overwritten if same pubkey and different addr, should be possible to have both, maybe even one-shots special command with dark address where entry is deleted after message sent!!! elif argv[0] == "add": nick = "" key = "" addr = "" # input sanity check if argc < 3: wOut(PSS_BUFPFX_ERROR, [bufs[currentPssName]], "!!!", "not enough arguments for add <TODO: help output>") return weechat.WEECHAT_RC_ERROR # puny human varnames nick = argv[1] key = argv[2] if argc == 4: addr = argv[3] else: addr = "0x" # backend add recipient call if not currentPss.add(nick, key, addr): wOut(PSS_BUFPFX_ERROR, [bufs[pssName]], "!!!", "add contact error: " + currentPss.error()['description']) return weechat.WEECHAT_RC_ERROR # refresh the plugin memory map version of the recipient wOut(PSS_BUFPFX_DEBUG, [], "!!!", "added key " + key + " to nick " + nick) nicks[key] = currentPss.get_contact(nick) remotekeys[nick] = key # append recipient to file for reinstating across sessions storeFile.write(nick + "\t" + key + "\t" + addr + "\t" + currentPss.key + "\n") # open the buffer if it doesn't exist buf_get(pssName, "chat", nick, True) wOut( PSS_BUFPFX_INFO, [bufs[pssName]], "!!!", "added contact '" + nicks[key].nick + "' to '" + pssName + "' (key: " + pss.label(key) + ", addr: " + pss.label(addr) + ")") # send a message to a recipient elif argv[0] == "send" or argv[0] == "msg": nick = "" msg = "" if argc < 2: wOut(PSS_BUFPFX_ERROR, [bufs[pssName]], "!!!", "not enough arguments for send") return weechat.WEECHAT_RC_ERROR nick = argv[1] if argc > 2: msg = " ".join(argv[2:]) # \todo handle hex address only if not currentPss.have_nick(nick): wOut(PSS_BUFPFX_ERROR, [bufs[pssName]], "!!!", "invalid nick " + nick) return weechat.WEECHAT_RC_ERROR buf = buf_get(pssName, "chat", nick, True) # \todo remove the bufs dict, since we can use weechat method for getting it bufs[weechat.buffer_get_string(buf, "name")] = buf # if no message body we've just opened the chat window if msg != "": if not pss.is_message(msg): wOut(PSS_BUFPFX_DEBUG, [bufs[pssName]], "", "invalid message " + msg) return weechat.WEECHAT_RC_ERROR return buf_in(pssName, buf, msg) # create/join existing chat room elif argv[0] == "join": room = "" if argc < 2: wOut(PSS_BUFPFX_ERROR, [bufs[pssName]], "!!!", "not enough arguments for join") return weechat.WEECHAT_RC_ERROR room = argv[1] wOut(PSS_BUFPFX_DEBUG, [], "!!!", "in join " + pssName) buf = buf_get(pssName, "room", room, True) # invite works in context of chat rooms, and translates in swarm terms to # adding one separate feed encoded with the invited peer's key # room argument can be omitted if command is issued om channel to invite to # note feeds are currently unencrypted elif argv[0] == "invite": nick = "" roomname = "" if argc < 2: wOut(PSS_BUFPFX_ERROR, [bufs[pssName]], "!!!", "not enough arguments for invite") # if missing channel argument get bufname command was issued in # and derive channel name from it if we can (fail if not) elif argc < 3: if ctx['t'] != PSS_BUFTYPE_ROOM: wOut(PSS_BUFPFX_ERROR, [bufs[pssName]], "!!!", "unknown channel '" + ctx['t'] + "'") return weechat.WEECHAT_RC_ERROR roomname = ctx['h'] else: roomname = argv[2] nick = argv[1] # check if room exists # if it does, perform invitation try: roombufname = buf_generate_name(pssName, "room", roomname) room = rooms[roombufname] pss_invite(pssName, nick, room) wOut(PSS_BUFPFX_DEBUG, [], "!!!", "added " + nick + " to " + roomname) # if neither the previous fail, add the nick to the buffer roombuf = weechat.buffer_search("python", roombufname) buf_room_add(roombuf, nick) except KeyError as e: # keyerror catches both try statements wOut(PSS_BUFPFX_ERROR, [buf], "!!!", "Unknown room or nick: " + str(e)) # output node key elif argv[0] == "key" or argv[0] == "pubkey": wOut(PSS_BUFPFX_INFO, [bufs[pssName]], pssName + ".key", currentPss.key) # output node base address elif argv[0] == "addr" or argv[0] == "address": wOut(PSS_BUFPFX_INFO, [bufs[pssName]], pssName + ".addr", currentPss.base) # set nick for pss node elif argv[0] == "nick": try: if len(argv) > 1: nick = pss.clean_nick(argv[1]) selfs[pssName].nick = nick wOut(PSS_BUFPFX_INFO, [bufs[pssName]], pssName, "nick is '" + selfs[pssName].nick + "'") except ValueError as e: wOut(PSS_BUFPFX_ERROR, [bufs[pssName]], "!!!", "Invalid nick: " + argv[1]) # stop connection # \todo also kill the subprocess # \todo ensure clean shutdown so conncet can be called over elif argv[0] == "stop": weechat.unhook(hookFds[pssName]) wOut(PSS_BUFPFX_INFO, [bufs[pssName]], "!!!", "disconnected from " + pssName) currentPss.close() #del psses[currentPssName] # invalid input else: return weechat.WEECHAT_RC_ERROR # all good return weechat.WEECHAT_RC_OK
def connect(url, data): global xd # ping the server, to see if it's online ping = requests.get(urljoin(url, "api")) if ping.status_code == requests.codes.teapot and "decent" in ping.json(): weechat.prnt( "", "weecent\tSuccessfully connected to Decent server %s." % url) elif ping.status_code in (requests.codes.ok, requests.codes.not_found): weechat.prnt( "", "weecent\t%s is not a valid Decent server, skipping." % url) del xd[url] return else: weechat.prnt("", "weecent\tCould not connect to %s, skipping." % url) del xd[url] return # login login_r = requests.post(urljoin(url, "api/login"), json=data) login_data = login_r.json() server_name = url.split("//")[1] if login_data["success"]: session_id = login_data["sessionID"] xd[url]["session_id"] = session_id channels_r = requests.get(urljoin(url, "api/channel-list"), {'sessionID': session_id}) if channels_r.json()['success']: channels = channels_r.json()['channels'] # create server buffer buffer_ = weechat.buffer_new(server_name, "server_input_cb", "", "server_close_cb", "") weechat.buffer_set(buffer_, "title", "Weecent testing!") weechat.buffer_set(buffer_, "localvar_set_no_log", "1") weechat.buffer_set(buffer_, "localvar_set_type", "server") weechat.buffer_set(buffer_, "localvar_set_url", url) weechat.buffer_set(buffer_, "localvar_set_server", server_name) xd[url]["buffer"] = buffer_ # create channel buffers xd[url]["channels"] = {} for channel in channels: xd[url]["channels"][channel["id"]] = {"name": channel["name"]} # set up buffer buffer_ = weechat.buffer_new(channel["name"], "send_message", "", "channel_close_cb", "") weechat.buffer_set(buffer_, "title", "Weecent testing!") weechat.buffer_set(buffer_, "nicklist", "1") weechat.buffer_set(buffer_, "nicklist_display_groups", "0") weechat.buffer_set(buffer_, "localvar_set_no_log", "1") weechat.buffer_set(buffer_, "localvar_set_type", "channel") weechat.buffer_set(buffer_, "localvar_set_channel", json.dumps(channel)) weechat.buffer_set(buffer_, "localvar_set_url", url) weechat.buffer_set(buffer_, "localvar_set_server", server_name) xd[url]["channels"][channel["id"]]["buffer"] = buffer_ # get scrollback scrollback_r = requests.get( urljoin(url, "api/channel/%s/latest-messages" % channel["id"])) messages = scrollback_r.json()["messages"] for m in messages: display_msg(buffer_, m, xd[url]) # get users users_r = requests.get(urljoin(url, "api/user-list")) users = users_r.json()["users"] group = weechat.nicklist_add_group( buffer_, "", "Users", "weechat.color.nicklist_group", 1) for u in users: weechat.nicklist_add_nick( buffer_, group, u["username"], "default" if u["online"] else "lightgrey", "", "lightgreen", 1) else: weechat.prnt("", "ono a bad happened") # create websocket if not "socket" in xd[url]: # wss or ws? use_secure = requests.get(urljoin(url, "api/should-use-secure")).json() protocol = "wss://" if use_secure["useSecure"] else "ws://" xd[url]['socket'] = websocket.create_connection( protocol + server_name, sslopt=sslopt_ca_certs) weechat.hook_fd(xd[url]['socket'].sock._sock.fileno(), 1, 0, 0, "recv_cb", "") xd[url]['socket'].sock.setblocking(0) else: weechat.prnt("", "ono a bad happened")
class weeNSServer : def __init__(self) : global weeNS_server_opt, weeNS_config_file, weeNS_config_server_section self.buffer = None self.hook_fd = None self.socket = None self.netbuffer = '' self.chats = [] self.contacts = {} self.options = { 'host' : weechat.config_new_option(weeNS_config_file, weeNS_config_server_section, 'host', 'string', 'Server Host (default: ns-server.epita.fr)', '', 0, 0, 'ns-server.epita.fr', 'ns-server.epita.fr', 0, '', '', '', '', '', ''), 'port' : weechat.config_new_option(weeNS_config_file, weeNS_config_server_section, 'port', 'string', 'Server Port (default: 4242)', '', 0, 0, '4242', '4242', 0, '', '', '', '', '', ''), 'login' : weechat.config_new_option(weeNS_config_file, weeNS_config_server_section, 'login', 'string', 'User login (ie: login_x)', '', 0, 0, 'login_x', 'login_x', 0, '', '', '', '', '', ''), 'password' : weechat.config_new_option(weeNS_config_file, weeNS_config_server_section, 'password', 'string', 'User password (ie: your SOCKS password)', '', 0, 0, 'xxxxxx', 'xxxxxx', 0, '', '', '', '', '', ''), 'location' : weechat.config_new_option(weeNS_config_file, weeNS_config_server_section, 'location', 'string', 'User location (ie: at home)', '', 0, 0, '-', '-', 0, '', '', '', '', '', ''), 'data' : weechat.config_new_option(weeNS_config_file, weeNS_config_server_section, 'data', 'string', 'User data (ie: j\'aime les chips)', '', 0, 0, '-', '-', 0, '', '', '', '', '', ''), 'contacts' : weechat.config_new_option(weeNS_config_file, weeNS_config_server_section, 'contacts', 'string', 'Comma separated login list (ie: sb,rn)', '', 0, 0, '', '', 0, '', '', '', '', '', '')} def getOption(self, opt_name) : return weechat.config_string(self.options[opt_name]) def getChatByRecipient(self, login = None, fd = None, create = False) : for chat in self.chats : if (fd is not None and chat.fd == fd) or (chat.login == login and chat.fd == fd) : return chat if create is True : return weeNSChat(self, login, fd) return None def getChatByBuffer(self, buffer) : for chat in self.chats : if chat.buffer == buffer : return chat return server def createBuffer(self) : if self.buffer == None : self.buffer = weechat.buffer_new('Netsoul', 'weeNS_buffer_input_cb', '', 'weeNS_buffer_close_cb', '') weechat.buffer_set(self.buffer, "nicklist", "1") weechat.buffer_set(self.buffer, "nicklist_display_groups", "1") weechat.buffer_set(self.buffer, "display", "auto") def connect(self) : self.createBuffer() self.disconnect() weechat.prnt(self.buffer, 'Connecting to %s:%s' % (self.getOption('host'), self.getOption('port'))) for res in socket.getaddrinfo(self.getOption('host'), self.getOption('port'), socket.AF_UNSPEC, socket.SOCK_STREAM, 0, socket.AI_PASSIVE) : af, socktype, proto, canonname, sa = res try : self.socket = socket.socket(af, socktype, proto) self.socket.connect(sa) except socket.error, msg: self.socket = None continue break if self.socket is None : weechat.prnt(self.buffer, 'Could not connect') self.hook_fd = weechat.hook_fd(self.socket.fileno(), 1, 0, 0, 'weeNS_hook_fd_cb', '')
def connect(self): """ Connect """ if not self.connect_webex(): return False if not self.buffer: bufname = f"{SCRIPT_NAME}.{self.domain}" self.buffer = weechat.buffer_search("python", bufname) if not self.buffer: self.buffer = weechat.buffer_new(bufname, "webex_buffer_input_cb", "", "webex_buffer_close_cb", "") if self.buffer: weechat.buffer_set(self.buffer, "short_name", SCRIPT_NAME) weechat.buffer_set(self.buffer, "input_multiline", "1") weechat.buffer_set(self.buffer, "localvar_set_type", "server") weechat.buffer_set(self.buffer, "localvar_set_server", self.domain) weechat.buffer_set(self.buffer, "display", "auto") self.prnt(f"Bienvenue {self.buddy.name}") # Join rooms that are in config rooms_to_join = self.get_config_value("autojoin_rooms") if rooms_to_join: for room_name in rooms_to_join.split(','): room = self.search_room(room_name, use_cache=True) if room: self.chats.append( Chat(self, room.title, room.id, "channel", auto=False)) # Join direct chats that are in config directs_to_join = self.get_config_value("autojoin_directs") if directs_to_join: for email in directs_to_join.split(','): if '@' not in email: email = f"{email}@{self.domain}" buddy = Buddy(self.get_person(email)) if buddy: if buddy.domain == self.domain: buf_name = buddy.name else: buf_name = buddy.email self.chats.append( Chat(self, buf_name, buddy.id, "private", auto=False)) # Autojoin last rooms autojoin_last = self.get_config_int_value("autojoin_last") if autojoin_last > 0: rooms = self.list_rooms(type=None, max=autojoin_last) if rooms: for room in rooms: if room.type == 'group': self.chats.append( Chat(self, room.title, room.id, "channel", auto=False)) else: person = self.get_person_from_id(room.id) if person: buddy = Buddy(self.get_person_from_id(room.id)) if buddy.domain == self.domain: buf_name = buddy.name else: buf_name = buddy.email self.chats.append( Chat(self, buf_name, buddy.id, "private", auto=False)) # SOCKET # We bind on 127.0.0.1:{port/8080} # So we need a proxy pass (like nginx or apache) # to forward the request to this socket if not self.sock: self.prnt("Starting socket") try: port = self.get_config_int_value("port") self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) self.sock.bind(("127.0.0.1", port)) self.sock.listen(5) self.prnt(f"Socket listening on {self.sock.getsockname()}") except Exception as e: self.prnt(f"Error while creating the HTTP server: {e}") self.disconnect() self.sock = None # WEECHAT HOOK if not self.hook: try: self.hook = weechat.hook_fd(self.sock.fileno(), 1, 0, 0, "socket_cb", "") except Exception as e: self.prnt(f"Error while creating the weechat hook: {e}") self.disconnect() self.hook = None # WEBEX HOOKBUSTER / Websocket proxy self.start_websocket(force=False) return True
def pss_handle(pssName, buf, args): # context is only used for acvie nodes ctx = EventContext() # parse cmd input # \todo remove consecutive whitespace argv = args.split(" ") argc = len(argv) # first we handle commands that are node independent # the connect command is the same for any context # \todo rollback on connect fail if argv[0] == "connect": host = "127.0.0.1" port = "8546" if argc < 2: wOut(PSS_BUFPFX_ERROR, [], "!!!", "invalid command <TODO insert help text>") ctx.set_node(argv[1]) if argc > 2: host = argv[2] if argc > 3: port = argv[3] if cache.have_node_name(ctx.get_node()): existingBuf = weechat.buffer_search("python", "pss.node." + ctx.get_node()) if existingBuf != "": wOut(PSS_BUFPFX_DEBUG, [], "", "pss " + ctx.get_node() + " already exists, changing to that buffer") weechat.buffer_set(bufs[ctx.get_node()], "display", "1") return weechat.WEECHAT_RC_OK if host == "": host = weechat.config_get_plugin(ctx.get_node() + "_url", host) if port == "": port = weechat.config_get_plugin(ctx.get_node() + "_port", port) wOut(PSS_BUFPFX_DEBUG, [], "", "pss " + ctx.get_node() + " already exists") # regardless of if we have the node already, store the connection parameters for later for this node name weechat.config_set_plugin(ctx.get_node() + "_url", host) weechat.config_set_plugin(ctx.get_node() + "_port", port) # if we made it here we don't have a buffer for this node already # so create it and merge the node buffer with core so we can do the neat ctrl-x trick bufs[ctx.get_node()] = weechat.buffer_new("pss.node." + ctx.get_node(), "buf_node_in", ctx.get_node(), "buf_close", ctx.get_node()) weechat.buffer_set(bufs[ctx.get_node()], "short_name", "pss."+ ctx.get_node()) weechat.buffer_set(bufs[ctx.get_node()], "title", "PSS '" + ctx.get_node() + "' | not connected") weechat.buffer_merge(bufs[ctx.get_node()], weechat.buffer_search_main()) weechat.buffer_set(bufs[ctx.get_node()], "display", "1") # now that we have the buffer up we have somewhere to write output relevant to this connection # we can proceed with connection in the pss instance wOut( PSS_BUFPFX_WARN, [bufs[ctx.get_node()]], "0-> 0", "connecting to '" + ctx.get_node() + "'" ) pssnode = pss.Pss(ctx.get_node(), host, port) if not pssnode.connect(): wOut(PSS_BUFPFX_ERROR, [bufs[ctx.get_node()]], "-1-x 0", "connect to '" + ctx.get_node() + "' failed: " + cache.get_pss(ctx.get_node()).error()['description']) return weechat.WEECHAT_RC_ERROR wOut(PSS_BUFPFX_OK, [bufs[ctx.get_node()]], "0---0", "connected to '" + ctx.get_node() + "'") _tmp_chat_queue_hash[ctx.get_node()] = "" cache.add_node(pssnode) wOut(PSS_BUFPFX_OK, [], "+++", "added pss " + ctx.get_node()) # save what we've accomplished so far in the context, to be passed to the hook ctx.parse_buffer(bufs[ctx.get_node()]) ctx.set_pss(cache.get_pss(ctx.get_node())) ctx.set_bzz(cache.get_active_bzz()) # \todo temporary solution, swarm gateway should be set explicitly or at least we need to be able to choose port ctxid = ctxstore.put(ctx) hookSocks.append(weechat.hook_connect("", host, 8500, 0, 0, "", "pss_connect", ctxid)) # start processing inputs on the websocket hookFds[ctx.get_node()] = weechat.hook_fd(cache.get_pss(ctx.get_node()).get_fd(), 1, 0, 0, "msgPipeRead", ctx.get_node()) hookTimers.append(weechat.hook_timer(PSS_FEEDBOX_PERIOD, 0, 0, "processFeedOutQueue", ctx.get_node())) # set own nick for this node # \todo use configurable global default nick # \todo clean up messy pubkey slicing (should be binary format in pss obj) cache.set_nodeself(ctx.get_node(), PSS_DEFAULT_NICK) return weechat.WEECHAT_RC_OK # get the context we're getting the command in # if we are not in pss context, # the we assume that the first argument is the name of the node # /pss oc add someone key addr # becomes # /pss add someone key addr # and "oc" is set to pssName # \todo consider exception for connect-command ctx.parse_buffer(buf) if ctx.is_root(): ctx.set_node(argv[0]) argv = argv[1:] argc -= 1 try: ctx.set_pss(cache.get_pss(ctx.get_node())) ctx.set_bzz(cache.get_active_bzz()) except: wOut( PSS_BUFPFX_ERROR, [], "!!!", "unknown pss connection '" + ctx.get_node() + "'" ) return weechat.WEECHAT_RC_ERROR # set configuation values if argv[0] == "set": if argc < 3: wOut(PSS_BUFPFX_ERROR, [], "!!!", "insufficient number of arguments <TODO help output") return weechat.WEECHAT_RC_ERROR k = argv[1] v = argv[2] # for now we handle privkeys directly # we will read keystore jsons in near future instead, though if k == "pk": try: privkey = pss.clean_privkey(v) except: wOut(PSS_BUFPFX_ERROR, [], "!!!", "invalid key format") return weechat.WEECHAT_RC_ERROR try: pssnode = cache.get_pss(ctx.get_node()) pssnode.set_account_write(privkey.decode("hex")) cache.update_node_contact_feed(pssnode) except KeyError as e: pass except ValueError as e: wOut(PSS_BUFPFX_ERROR, [], "!!!", "set account fail: " + str(e)) return weechat.WEECHAT_RC_ERROR else: wOut(PSS_BUFPFX_ERROR, [], "!!!", "unknown config key") return weechat.WEECHAT_RC_ERROR wOut(PSS_BUFPFX_DEBUG, [], "!!!", "set pk to " + v + " for " + ctx.get_node()) weechat.WEECHAT_RC_OK # add a recipient to the address books of plugin and node # \todo currently overwritten if same pubkey and different addr, should be possible to have both, maybe even one-shots special command with dark address where entry is deleted after message sent!!! elif argv[0] == "add": nick = "" pubkeyhx = "" overlayhx = "" # input sanity check if argc < 3: wOut( PSS_BUFPFX_ERROR, [ctx.get_buffer()], "!!!", "not enough arguments for add <TODO: help output>" ) return weechat.WEECHAT_RC_ERROR # puny human varnames nick = argv[1] pubkeyhx = argv[2] if argc == 4: overlayhx = argv[3] else: overlayhx = "0x" # backend add recipient call pubkey = pss.clean_pubkey(pubkeyhx).decode("hex") overlay = pss.clean_overlay(overlayhx).decode("hex") try: newcontact = pss.PssContact(nick, ctx.get_pss().get_public_key()) newcontact.set_public_key(pubkey) newcontact.set_overlay(overlay) ctx.get_pss().add(newcontact) cache.add_contact(newcontact, True) except Exception as e: wOut( PSS_BUFPFX_ERROR, [ctx.get_buffer()], "!!!", "add contact error: " + repr(e) ) return weechat.WEECHAT_RC_ERROR ctx.reset(PSS_BUFTYPE_CHAT, ctx.get_node(), nick) # refresh the plugin memory map version of the recipient wOut( PSS_BUFPFX_DEBUG, [], "!!!", "added key " + pubkeyhx + " to nick " + nick + " node " + ctx.get_node() ) # retrieve the buffer (create if it doesn't exist) buf_get(ctx, True) wOut( PSS_BUFPFX_INFO, [ctx.get_buffer()], "!!!", "added contact '" + ctx.get_name() + "' to '" + ctx.get_node() + "' (key: " + pss.label(pubkeyhx) + ", addr: " + pss.label(overlayhx) + ")" ) # send a message to a recipient elif argv[0] == "send" or argv[0] == "msg": nick = "" msg = "" # verify input if argc < 2: wOut( PSS_BUFPFX_ERROR, [ctx.get_buffer()], "!!!", "not enough arguments for send" ) return weechat.WEECHAT_RC_ERROR nick = pss.clean_nick(argv[1]) if argc > 2: msg = " ".join(argv[2:]) # check that the contact is known in the cache contact = None try: contact = cache.get_contact_by_nick(nick) except: wOut( PSS_BUFPFX_ERROR, [ctx.get_buffer()], "!!!", "invalid nick " + nick ) return weechat.WEECHAT_RC_ERROR ctx.reset(PSS_BUFTYPE_CHAT, ctx.get_node(), nick) buf = buf_get(ctx, True) # if no message body we've just opened the chat window if msg != "": if not pss.is_message(msg): wOut( PSS_BUFPFX_DEBUG, [ctx.get_buffer()], "", "invalid message " + msg ) return weechat.WEECHAT_RC_ERROR return buf_in(ctx.get_node(), buf, msg) # create/join existing chat room # \todo broken elif argv[0] == "join": room = "" if argc < 2: wOut( PSS_BUFPFX_ERROR, [ctx.get_buffer()], "!!!", "not enough arguments for join" ) return weechat.WEECHAT_RC_ERROR room = argv[1] ctx.reset(PSS_BUFTYPE_ROOM, ctx.get_node(), room) if not ctx.get_name() in _tmp_room_queue_hash: _tmp_room_queue_hash[ctx.get_name()] = pss.zerohsh # start buffer for room buf_get(ctx, True) # invite works in context of chat rooms, and translates in swarm terms to # adding one separate feed encoded with the invited peer's key # room argument can be omitted if command is issued om channel to invite to # note feeds are currently unencrypted # \todo broken elif argv[0] == "invite": nick = "" roomname = "" if argc < 2: wOut( PSS_BUFPFX_ERROR, [ctx.get_buffer()], "!!!", "not enough arguments for invite" ) # if missing channel argument get bufname command was issued in # and derive channel name from it if we can (fail if not) elif argc < 3: if not ctx.is_room(): wOut( PSS_BUFPFX_ERROR, [ctx.get_buffer()], "!!!", "unknown channel '" + ctx.get_name() + "'" ) return weechat.WEECHAT_RC_ERROR else: ctx.set_name(argv[2]) nick = pss.clean_nick(argv[1]) # check if room exists # if it does, perform invitation try: #roombufname = buf_generate_name(pssName, "room", roomname) roombufname = ctx.to_buffer_name() room = cache.get_room(ctx.get_name()) #roombufname) pss_invite(pssName, nick, room) wOut( PSS_BUFPFX_DEBUG, [], "!!!", "added " + nick + " to " + ctx.get_name() ) # if neither the previous fail, add the nick to the buffer roombuf = weechat.buffer_search("python", roombufname) buf_room_add(roombuf, nick) except KeyError as e: # keyerror catches both try statements wOut( PSS_BUFPFX_ERROR, [ctx.get_buffer()], "!!!", "Unknown room or nick: " + str(e) ) # output node key elif argv[0] == "key" or argv[0] == "pubkey": wOut( PSS_BUFPFX_INFO, [ctx.get_buffer()], ctx.get_node() + ".key", ctx.get_pss().get_public_key().encode("hex") ) # output node base address elif argv[0] == "addr" or argv[0] == "address": wOut( PSS_BUFPFX_INFO, [ctx.get_buffer()], ctx.get_node() + ".addr", ctx.get_pss().get_overlay().encode("hex") ) # set nick for pss node elif argv[0] == "nick": try: if len(argv) > 1: nick = pss.clean_nick(argv[1]) cache.set_nodeself(ctx.get_node(), nick) wOut( PSS_BUFPFX_INFO, [ctx.get_buffer()], ctx.get_node(), "nick is '" + cache.get_nodeself(ctx.get_node()) + "'" ) except ValueError as e: wOut( PSS_BUFPFX_ERROR, [ctx.get_buffer()], "!!!", "Invalid nick: " + argv[1] ) # stop connection # \todo also kill the subprocess # \todo ensure clean shutdown so conncet can be called over elif argv[0] == "stop": weechat.unhook(hookFds[ctx.get_node()]) wOut( PSS_BUFPFX_INFO, [ctx.get_buffer()], "!!!", "disconnected from " + ctx.get_node() ) cache.close_node(ctx.get_node()) # invalid input else: return weechat.WEECHAT_RC_ERROR # all good return weechat.WEECHAT_RC_OK