-#!/usr/bin/env ruby
+#!/usr/bin/python3
# Filename: grml-paste
-# Purpose: paste files to the online grml paste bot
-# Authors: grml-team (grml.org), (c) 2007 Nico Golde <nico@grml.org>
-# Bug-Reports: see http://grml.org/bugs/
-# License: This file is licensed under the GPL v2
-##########################################################################
-
-require 'uri'
-require 'net/http'
-
-url = URI.parse('http://paste.grml.org/paste')
-
-def usage
- $stderr.puts "usage: #{$0} [-n nick] [-s summary] [-f source] [-h|--help]\n"
- $stderr.puts "\t -n <nick>\tset your nickname (defaults to Anonymuos)"
- $stderr.puts "\t -s <summary>\tspecify a summary of your paste (defaults to none)"
- $stderr.puts "\t -f <source>\tsets the file to read from, you don't need this for reading from stdin"
- $stderr.puts "\t --help\t\tprint this help"
- Kernel.exit(1)
-end
-
-file = nil
-summary = "none"
-nick = "Anonymous"
-channel = "#grml"
-text = ""
-
-ARGV.each_index do |i|
- if ARGV[i] == '-h' or ARGV[i] == '--help' then
- usage
- elsif ARGV[i] == '-n' and ARGV[i+1] != nil then
- nick = ARGV[i+1]
- elsif ARGV[i] == '-s' and ARGV[i+1] != nil then
- summary = ARGV[i+1]
- elsif ARGV[i] == '-f' and ARGV[i+1] != nil then
- file = ARGV[i+1]
- end
-end
-
-if file == nil or file == "-"
- f = STDIN
-else
- begin
- f = File.open(file)
- rescue
- $stderr.puts "Error: couldn't open file: #{file}"
- Kernel.exit(1)
- end
-end
-
-f.each_line do |line|
- text << line
-end
-
-begin
- res = Net::HTTP.post_form(url,{'Paste it' => 'Paste it', 'paste' => text, 'channel' => channel, 'summary' => summary, 'nick' => nick})
-rescue
- $stderr.puts "Unable to post HTTP request"
- Kernel.exit(1)
-end
-
-results = res.body.scan(/<a href='http:\/\/paste.grml.org\/[0-9]+'/)
-result = ""
-if results.size > 0 then
- result = results[0].sub(/<a href='(http:\/\/paste.grml.org\/[0-9]+)'/, '\1')
-end
-
-if result == "" then
- print "Failed to paste, please retry\n"
-else
- print "You can find your paste on: " + result + "\n"
-end
-
-## END OF FILE #################################################################
+# Purpose: XmlRpc interface client to paste.grml.org
+# Author: Michael Gebetsroither <gebi@grml.org>
+# 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>
+
+ <digest> 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>
+
+ <id> Id of paste you want to receive.
+ '''
+ id = self.args_.pop(0)
+ result = self._callProxy(lambda s: s.paste.getPaste(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: <url>
+
+ <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: <url>
+
+ <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: <url>
+
+ <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: <action>
+
+ <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 <args>\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])