def invite(self, user, channel): """ Send a channel invite to a user. """ userOut = format.encodeOut(user) channelOut = format.encodeOut(channel) self.sendLine("INVITE %s %s" % (userOut, channelOut)) log.chatlog.info('[INVITE->%s] %s' % (userOut, channelOut))
def cnotice(self, channel, user, message): """ Send a CNOTICE. This allows channel ops to bypass server flood limits when sending a notice to users in their channel. """ msgOut = format.encodeOut(msg) userOut = format.encodeOut(user) channelOut = format.encodeOut(channel) self.sendLine("CNOTICE %s %s :%s" % (userOut, channelOut, msgOut,))
def cprivmsg(self, channel, user, msg): """ Send a CPRIVMSG. This allows channel ops to bypass server flood limits when messaging users in their channel. """ msgOut = format.encodeOut(msg) userOut = format.encodeOut(user) channelOut = format.encodeOut(channel) self.sendLine("CPRIVMSG %s %s :%s" % (userOut, channelOut, msgOut,))
def noteout(self, user, msg): """ Send a notice to a user. """ msgOut = format.encodeOut(msg) userOut = format.encodeOut(user) self.notice(user=userOut, message=msgOut) # strip color codes log.chatlog.info('[NTE->%s]%s' % (userOut, format.strip(msgOut)))
def privout(self, user, msg): """ Send a message to a user. """ msgOut = format.encodeOut(msg) userOut = format.encodeOut(user) self.msg(user=userOut, message=msgOut) # strip color codes log.chatlog.info('[PRV->%s]%s' % (userOut, format.strip(msgOut)))
def pubout(self, channel, msg): """ Send a message to a channel. """ msgOut = format.encodeOut(msg) channelOut = format.encodeOut(channel) self.say(channel=channelOut, message=msgOut) # strip color codes log.chatlog.info('[PUB->%s]%s' % (channelOut, format.strip(msgOut)))
def join(self, channel, key=None): """ Join a channel. """ channelOut = format.encodeOut(channel) if key: keyOut = format.encodeOut(key) irc.IRCClient.join(self, channelOut, keyOut) else: irc.IRCClient.join(self, channelOut)
def actout(self,channel, msg): """ Send an action (/me command) to a channel. """ msgOut = format.encodeOut(msg) channelOut = format.encodeOut(channel) self.me(channel=channelOut, action=msgOut) # strip color codes log.chatlog.info('[ACT->%s]%s' % (channelOut, format.strip(msgOut)))
def replyout(self, channel, user, msg): """ Send a reply. If channel is None, the reply is sent to the user; otherwise, it is sent to the channel. Use this in plugins or commands when an incoming message can be either from a channel or a user and the outgoing message should be resent to the source. """ msgOut = format.encodeOut(msg) userOut = format.encodeOut(user) channelOut = format.encodeOut(channel) if channel is None: self.privout(userOut, msgOut) else: self.pubout(channelOut, msgOut)
def getApiResponse(self, title): """ Make an API request to the Wiki for an article and return the parsed JSON response. The article content contained in the response is parsed as HTML, not raw wikicode. The response is cached for later use. """ # if already cached, return that if title == self.lastTitle: return self.lastResponse queryParams = { 'action' : 'query', 'titles' : format.encodeOut(title), 'prop' : 'revisions', 'rvprop' : 'content', 'rvsection' : 0, 'rvlimit': 1, 'rvparse': 1, 'redirects' : 1, 'format' : 'json' } apiUrl = "%s%s?%s"%(self.wikiUrl, self.wikiApi, urlencode(queryParams)) try: self.lastResponse = json.loads(urlopen(apiUrl).readline(), 'UTF-8') self.lastTitle = title return self.lastResponse except URLError as e: if hasattr(e, 'reason'): log.logging.error("reference.Wiki: Cannot access <%s>." +\ "Error %i: %s", apiUrl, e.reason[0], e.reason[1]) elif hasattr(e, 'code'): log.logging.error("reference.Wiki: Cannot access <%s>. " +\ "Server returned status: %i", apiUrl, e.code) return None except: log.logging.exception("reference.Wiki: An error occurred " +\ "retrieving the content of '%s' <%s> (maybe malformed JSON?)",\ format.encodeOut(title), apiUrl) return None
def getPreview(self, title, maxlen): """Get a preview of the article (the first few hundred characters). This assumes the article exists (i.e. check self.articleExists first!) If an error accessing the article occurs, an empty string is returned. If the data received is malformed, None is returned.""" # If preview length is 0, no preview; exit early if maxlen <= 0: return "" results = self.getApiResponse(title) # if getApiResponse() returns None, failed to retrieve or parse data if not results: return None try: htmlText = results['query']['pages'].values()[0]['revisions'][0]['*'] except (KeyError, IndexError, TypeError) as e: log.logging.exception("reference.Wiki: A %s exception occurred " +\ "while retrieving article text for '%s': %s",\ e.__class__.__name__, format.encodeOut(title), str(e)) return None except: log.logging.exception("reference.Wiki: An error occurred while " +\ "retrieving the content of '%s' (maybe malformed JSON?)",\ format.encodeOut(title)) return None previewText = self.getFirstParagraph(htmlText) # encode: so smartTruncate() counts bytes, not Unicode chars # decode: reconverts it back to Unicode for return previewText = self.smartTruncate( previewText.encode('utf-8', 'replace'),\ maxlen).decode('utf-8', 'replace') return previewText
def encodeOut(msg): """ DEPRECATED. Maintained for backwards compatibility. Use pyGBot.format.encodeOut(). """ log.logger.warning("DEPRECATED: pyGBot.core.encodeOut() is deprecated. " +\ "Use format.encodeOut().") return format.encodeOut(msg)
def changenick(self, newnick): newnickOut = format.encodeOut(newnick) self.setNick(newnickOut)
def part(self, channel, reason=None): """ Part a channel. """ channelOut = format.encodeOut(channel) reasonOut = format.encodeOut(reason) irc.IRCClient.part(self, channelOut, reasonOut)
def getUrl(self, title): """Returns the URL of the article.""" urlTitle = quote(format.encodeOut( self.getResolvedTitle(title).replace(' ', '_'))) return "%s%s/%s" % (self.wikiUrl, self.wikiBase, urlTitle)
def command(self, channel, user, args): """ Execute a command. Searches for an article on the wiki, and returns a string containing the article title, URL and a short extract (or an error message). The expected arguments args is a dictionary of the form {'query': searchterms, 'name': wikiName, 'url': wikiUrl, 'api': wikiApi, 'base': wikiBase}, where searchterms is the search terms, and the other arguments have the same meaning as the configuration options of the same name. The first argument is required, but the latter arguments are optional and override the configuration settings for Wiki name, URL, etc. if present.""" # if plugin inactive, exit if not self.active: return "" # for logging purposes if not channel: source = 'msg' else: source = channel # Set wiki settings if provided self.pushWiki() self.loadWiki(args) # Error if no query specified or invalid query if 'query' not in args: log.logger.info("reference.Wiki: No subject passed for lookup " +\ "by %s in %s on %s <%s>",\ user, source, format.encodeOut(self.wikiName), self.wikiUrl) return u"Please provide a subject to search %s" % self.wikiName # Start processing the command query = args['query'].strip() outputList = [] # [wikiname, articlename, (previewText), url] isFound = self.articleExists(query) if isFound: invalidArticle = False # for logging purposes resolvedTitle = self.getResolvedTitle(query) outputList.append( "".join([self.wikiName, " -"]) ) outputList.append( "".join(["\x02", resolvedTitle, "\x02:"]) ) if self.useShortUrl: outputList.append( self.getShortUrl(resolvedTitle) ) else: outputList.append( self.getUrl(resolvedTitle) ) # Preview length = max length - current length (all as bytes) # (+ 1 for additional " " needed to insert preview text) previewLen = min(510, self.maxMessageSize)\ - (len(format.encodeOut(u' '.join(outputList)))+1) # use query, not redirectTitle, to make use of cache and not redownload previewText = self.getPreview(query, previewLen) # if getPreview received malformed data, assume an invalid page if previewText is None: outputList = ["Sorry, I can't look that up on %s." % self.wikiName] log.logger.warning("reference.Wiki: Attempted lookup of " +\ "non-article '%s' by %s in %s on %s <%s>",\ format.encodeOut(query), user, source,\ format.encodeOut(self.wikiName), self.wikiUrl) invalidArticle = True # for logging purposes # if getPreview returned text, add to output elif len(previewText) > 0: outputList.insert(2, previewText) # If we didn't fall under the "I can't look that up" case, log a successful lookup if not invalidArticle: log.logger.info("reference.Wiki: Found article '%s' for " +\ "query '%s' by %s in %s on %s <%s>",\ format.encodeOut(resolvedTitle), format.encodeOut(query),\ user, source, format.encodeOut(self.wikiName), self.wikiUrl) elif isFound == False: outputList.append( u"Sorry, no %s page exists for '%s'."\ % (self.wikiName, query) ) log.logger.info("reference.Wiki: No article found for query " +\ "'%s' by %s in %s on %s <%s>",\ format.encodeOut(query), user, source,\ format.encodeOut(self.wikiName), self.wikiUrl) else: # None, meaning an error occurred outputList.append(u"Sorry, an error occurred searching for %s page '%s'."\ % (self.wikiName, format.encodeOut(query))) outputList.append(u"Maybe it works for you:") if self.useShortUrl: outputList.append( self.getShortUrl(query) ) else: outputList.append( self.getUrl(query) ) log.logger.error("reference.Wiki: An error occurred retrieving " +\ "or parsing the API response for query '%s' by " +\ "%s in %s on %s <%s>",\ format.encodeOut(query), user, source,\ format.encodeOut(self.wikiName), self.wikiUrl) # Restore options set in bot configuration self.popWiki() return u' '.join(outputList)