#!/usr/bin/python3 # Filename: grml-paste # Purpose: XmlRpc interface client to paste.grml.org # Author: Michael Gebetsroither # License: This file is licensed under the GPL v2. ################################################################################ import sys from xmlrpc.client import ServerProxy import optparse import inspect import getpass # program defaults DEFAULT_SERVER = "http://paste.grml.org/server.pl" class ActionFailedException(Exception): """Thrown if server returned an error""" def __init__(self, errormsg, ret): Exception.__init__(self, errormsg, ret) def what(self): """Get errormessage""" return self.args[0] def dwhat(self): """Get more verbose errormessage""" return self.args[1] class Action(object): def __init__(self, args, opts): self.args_ = args self.opts_ = opts def _createProxy(self): return ServerProxy(self.opts_.server, verbose=False) def _callProxy(self, functor, server=None): """Wrapper for xml-rpc calls to server which throws an ActionFailedException on error""" if server is None: server = self._createProxy() ret = functor(server) if ret["rc"] != 0: raise ActionFailedException(ret["statusmessage"], ret) return ret def call(self, method_name): """External Interface to call the appropriate action""" return self.__getattribute__(method_name)() def actionAddPaste(self): """Add paste to the server: <1.line> <2.line> ... default Read paste from stdin. [text] Every argument on the commandline will be interpreted as a seperate line of paste. """ server = self._createProxy() o = self.opts_ code = self.args_ if len(self.args_) == 0: code = [i.rstrip() for i in sys.stdin.readlines()] code = "\n".join(code) result = self._callProxy(lambda s: s.paste.addPaste(code, o.name, o.expire * 3600, o.lang, o.private), server) return result["statusmessage"], result def actionDelPaste(self): """Delete paste from server: Digest of paste you want to remove. """ digest = self.args_.pop(0) result = self._callProxy(lambda s: s.paste.deletePaste(digest)) return result["statusmessage"], result def actionGetPaste(self): """Get paste from server: Id of paste you want to receive. """ paste_id = self.args_.pop(0) result = self._callProxy(lambda s: s.paste.getPaste(paste_id)) return result["code"], result def actionGetLangs(self): """Get supported language highlighting types from server""" result = self._callProxy(lambda s: s.paste.getLanguages()) return "\n".join(result["langs"]), result def actionAddShortUrl(self): """Add short-URL: Short-URL to add """ url = self.args_.pop(0) result = self._callProxy(lambda s: s.paste.addShortURL(url)) return result["url"], result def actionGetShortUrl(self): """Resolve short-URL: Short-URL to get clicks of """ url = self.args_.pop(0) result = self._callProxy(lambda s: s.paste.resolveShortURL(url)) return (result["url"], result) def actionGetShortUrlClicks(self): """Get clicks of short-URL: Short-URL to get clicks of """ url = self.args_.pop(0) result = self._callProxy(lambda s: s.paste.ShortURLClicks(url)) return result["count"], result def actionHelp(self): """Print more verbose help about specific action: Topic on which you need more verbose help. """ if len(self.args_) < 1: alias = "help" else: alias = self.args_.pop(0) if alias in actions: fun = actions[alias] print(inspect.getdoc(self.__getattribute__(fun))) print("\naliase: " + " ".join([i for i in actions_r[fun] if i != alias])) else: print("Error: No such command - %s" % (alias)) OPT_PARSER.print_usage() sys.exit(0) # actionAddPaste -> [add, a] actions_r = {} # add -> actionAddPaste # a -> actionAddPaste actions = {} # option parser OPT_PARSER = None ## # MAIN ## if __name__ == "__main__": action_spec = ["actionAddPaste add a", "actionDelPaste del d rm", "actionGetPaste get g", "actionGetLangs getlangs gl langs l", "actionAddShortUrl addurl", "actionGetShortUrl geturl", "actionGetShortUrlClicks getclicks", "actionHelp help"] for i in action_spec: aliases = i.split() cmd = aliases.pop(0) actions_r[cmd] = aliases for (k, v) in actions_r.items(): for i in v: actions[i] = k usage = "usage: %prog [options] ACTION \n\n" +\ "actions:\n" +\ "\n".join(["%12s\t%s" % (v[0], inspect.getdoc(getattr(Action, k)).split("\n")[0]) for (k, v) in actions_r.items()]) running_user = getpass.getuser() parser = optparse.OptionParser(usage=usage) parser.add_option("-n", "--name", default=running_user, help="Name of poster") parser.add_option("-e", "--expire", type=int, default=72, metavar="HOURS", help="Time at wich paste should expire") parser.add_option("-l", "--lang", default="Plain", help="Type of language to highlight") parser.add_option("-p", "--private", action="count", dest="private", default=0, help="Create hidden paste"), parser.add_option("-s", "--server", default=DEFAULT_SERVER, help="Paste server") parser.add_option("-v", "--verbose", action="count", default=0, help="More output") (opts, args) = parser.parse_args() OPT_PARSER = parser if len(args) == 0: parser.error("Please provide me with an action") elif args[0] in actions: cmd = args.pop(0) action = Action(args, opts) try: (msg, ret) = action.call(actions[cmd]) if opts.verbose == 0: print(msg) else: print(ret) except ActionFailedException as e: sys.stderr.write("Server Error: %s\n" % e.what()) if opts.verbose > 0: print(e.dwhat()) sys.exit(1) else: parser.error("Unknown action: %s" % args[0])