#!/usr/bin/env python # Copyright (c) 2009-2012, Mario Vilas # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are met: # # * Redistributions of source code must retain the above copyright notice, # this list of conditions and the following disclaimer. # * Redistributions in binary form must reproduce the above copyright # notice,this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # * Neither the name of the copyright holder nor the names of its # contributors may be used to endorse or promote products derived from # this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE # ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE # POSSIBILITY OF SUCH DAMAGE. """ Unofficial pastebin.com API for Python by Mario Vilas (mvilas at gmail dot com) Unlike the official API, this one doesn't require an API key. U{http://breakingcode.wordpress.com/2012/01/27/pasting-anonymously-to-pastebin-com/} U{http://breakingcode.wordpress.com/2010/03/06/using-the-pastebin-api-with-python/} Usage examples:: >>> from pastebin import submit >>> >>> # Submit a simple text message. ... url = submit("This is a test message.") >>> print url http://pastebin.com/G4YWsB1a >>> >>> # Submit a simple "hello world" code in Python. ... # Paste expires in 10 minutes. ... url = submit("print \"Hello world!\"", ... paste_format="python", ... paste_expire_date="10M") >>> print url http://pastebin.com/rKEVDWHP >>> >>> # Submit Apache's logs as a private paste. ... # Give the paste a title. ... url = submit(open('/var/log/apache/access.log', 'r').read(), ... paste_format="apache", ... paste_private=True, ... paste_name="My Apache access logs") >>> print url http://pastebin.com/kfepMRLh >>> """ __all__ = ['submit', 'Pastebin', 'PastebinError'] import urllib class PastebinError(RuntimeError): """ Pastebin API error. The error message returned by the web application is stored as the Python exception message. """ class Pastebin(object): """ Unofficial python interface to the Pastebin legacy API. Unlike the official API, this one doesn't require an API key, so it's virtually anonymous. @warn: To be B{completely} anonymous you'll have to hide your IP address as well, either by using an HTTP proxy or the Tor network. To use an HTTP proxy, set the HTTP_PROXY environment variable as per the documentation of the Python standard C{urllib} module: U{http://docs.python.org/library/urllib.html} To go through the Tor network, consult the following Wiki document: U{https://trac.torproject.org/projects/tor/wiki/doc/TorifyHOWTO} @type paste_expire_date: tuple(str) @cvar paste_expire_date: Valid C{paste_expire_date} values, see L{submit}. @type paste_format: tuple(str) @cvar paste_format: Valid C{parse_format} values, see L{submit}. """ # Base domain name _base_domain = 'pastebin.com' # Valid Pastebin URLs begin with this string _prefix_url = 'http://%s/' % _base_domain # Valid Pastebin URLs with a custom subdomain begin with this string _subdomain_url = 'http://%%s.%s/' % _base_domain # URL to the POST API _api_url = 'http://%s/api_public.php' % _base_domain # Valid paste_expire_date values paste_expire_date = ('N', '10M', '1H', '1D', '1M') # Valid parse_format values paste_format = ( '4cs', # 4CS '6502acme', # 6502 ACME Cross Assembler '6502kickass', # 6502 Kick Assembler '6502tasm', # 6502 TASM/64TASS 'abap', # ABAP 'actionscript', # ActionScript 'actionscript3', # ActionScript 3 'ada', # Ada 'algol68', # ALGOL 68 'apache', # Apache Log 'applescript', # AppleScript 'apt_sources', # APT Sources 'asm', # ASM (NASM) 'asp', # ASP 'autoconf', # autoconf 'autohotkey', # Autohotkey 'autoit', # AutoIt 'avisynth', # Avisynth 'awk', # Awk 'bascomavr', # BASCOM AVR 'bash', # Bash 'basic4gl', # Basic4GL 'bibtex', # BibTeX 'blitzbasic', # Blitz Basic 'bnf', # BNF 'boo', # BOO 'bf', # BrainFuck 'c', # C 'c_mac', # C for Macs 'cil', # C Intermediate Language 'csharp', # C# 'cpp', # C++ 'cpp-qt', # C++ (with QT extensions) 'c_loadrunner', # C: Loadrunner 'caddcl', # CAD DCL 'cadlisp', # CAD Lisp 'cfdg', # CFDG 'chaiscript', # ChaiScript 'clojure', # Clojure 'klonec', # Clone C 'klonecpp', # Clone C++ 'cmake', # CMake 'cobol', # COBOL 'coffeescript', # CoffeeScript 'cfm', # ColdFusion 'css', # CSS 'cuesheet', # Cuesheet 'd', # D 'dcs', # DCS 'delphi', # Delphi 'oxygene', # Delphi Prism (Oxygene) 'diff', # Diff 'div', # DIV 'dos', # DOS 'dot', # DOT 'e', # E 'ecmascript', # ECMAScript 'eiffel', # Eiffel 'email', # Email 'epc', # EPC 'erlang', # Erlang 'fsharp', # F# 'falcon', # Falcon 'fo', # FO Language 'f1', # Formula One 'fortran', # Fortran 'freebasic', # FreeBasic 'freeswitch', # FreeSWITCH 'gambas', # GAMBAS 'gml', # Game Maker 'gdb', # GDB 'genero', # Genero 'genie', # Genie 'gettext', # GetText 'go', # Go 'groovy', # Groovy 'gwbasic', # GwBasic 'haskell', # Haskell 'hicest', # HicEst 'hq9plus', # HQ9 Plus 'html4strict', # HTML 'html5', # HTML 5 'icon', # Icon 'idl', # IDL 'ini', # INI file 'inno', # Inno Script 'intercal', # INTERCAL 'io', # IO 'j', # J 'java', # Java 'java5', # Java 5 'javascript', # JavaScript 'jquery', # jQuery 'kixtart', # KiXtart 'latex', # Latex 'lb', # Liberty BASIC 'lsl2', # Linden Scripting 'lisp', # Lisp 'llvm', # LLVM 'locobasic', # Loco Basic 'logtalk', # Logtalk 'lolcode', # LOL Code 'lotusformulas', # Lotus Formulas 'lotusscript', # Lotus Script 'lscript', # LScript 'lua', # Lua 'm68k', # M68000 Assembler 'magiksf', # MagikSF 'make', # Make 'mapbasic', # MapBasic 'matlab', # MatLab 'mirc', # mIRC 'mmix', # MIX Assembler 'modula2', # Modula 2 'modula3', # Modula 3 '68000devpac', # Motorola 68000 HiSoft Dev 'mpasm', # MPASM 'mxml', # MXML 'mysql', # MySQL 'newlisp', # newLISP 'text', # None 'nsis', # NullSoft Installer 'oberon2', # Oberon 2 'objeck', # Objeck Programming Langua 'objc', # Objective C 'ocaml-brief', # OCalm Brief 'ocaml', # OCaml 'pf', # OpenBSD PACKET FILTER 'glsl', # OpenGL Shading 'oobas', # Openoffice BASIC 'oracle11', # Oracle 11 'oracle8', # Oracle 8 'oz', # Oz 'pascal', # Pascal 'pawn', # PAWN 'pcre', # PCRE 'per', # Per 'perl', # Perl 'perl6', # Perl 6 'php', # PHP 'php-brief', # PHP Brief 'pic16', # Pic 16 'pike', # Pike 'pixelbender', # Pixel Bender 'plsql', # PL/SQL 'postgresql', # PostgreSQL 'povray', # POV-Ray 'powershell', # Power Shell 'powerbuilder', # PowerBuilder 'proftpd', # ProFTPd 'progress', # Progress 'prolog', # Prolog 'properties', # Properties 'providex', # ProvideX 'purebasic', # PureBasic 'pycon', # PyCon 'python', # Python 'q', # q/kdb+ 'qbasic', # QBasic 'rsplus', # R 'rails', # Rails 'rebol', # REBOL 'reg', # REG 'robots', # Robots 'rpmspec', # RPM Spec 'ruby', # Ruby 'gnuplot', # Ruby Gnuplot 'sas', # SAS 'scala', # Scala 'scheme', # Scheme 'scilab', # Scilab 'sdlbasic', # SdlBasic 'smalltalk', # Smalltalk 'smarty', # Smarty 'sql', # SQL 'systemverilog', # SystemVerilog 'tsql', # T-SQL 'tcl', # TCL 'teraterm', # Tera Term 'thinbasic', # thinBasic 'typoscript', # TypoScript 'unicon', # Unicon 'uscript', # UnrealScript 'vala', # Vala 'vbnet', # VB.NET 'verilog', # VeriLog 'vhdl', # VHDL 'vim', # VIM 'visualprolog', # Visual Pro Log 'vb', # VisualBasic 'visualfoxpro', # VisualFoxPro 'whitespace', # WhiteSpace 'whois', # WHOIS 'winbatch', # Winbatch 'xbasic', # XBasic 'xml', # XML 'xorg_conf', # Xorg Config 'xpp', # XPP 'yaml', # YAML 'z80', # Z80 Assembler 'zxbasic', # ZXBasic ) @classmethod def submit(cls, paste_code, paste_name = None, paste_private = None, paste_expire_date = None, paste_format = None): """ Submit a code snippet to Pastebin. @type paste_code: str @param paste_code: Code or text to send to U{http://pastebin.com}. @type paste_name: str @param paste_name: (Optional) Name of the author of the paste. Default is to paste anonymously. @type paste_private: bool @param paste_private: (Optional) C{True} if the paste is private (only visible with the link), C{False} if it's public (indexed and searchable). The Pastebin FAQ (U{http://pastebin.com/faq}) claims private pastes are not indexed by search engines (aka Google). @type paste_expire_date: str @param paste_expire_date: (Optional) Expiration date for the paste. Once past this date the paste is deleted automatically. Valid values are found in the L{Pastebin.paste_expire_date} class member. If not provided, the paste never expires. @type paste_format: str @param paste_format: (Optional) Programming language of the code being pasted. This enables syntax highlighting when reading the code in U{http://pastebin.com}. Default is no syntax highlighting (text is just text and not source code). @rtype: str @return: Returns the URL to the newly created paste. @raise PastebinError: The Pastebin API has returned an error message. @raise IOError: An error occurred when contacting the Pastebin web application. This is typically caused by network errors. """ # Code snippet to submit argv = { 'paste_code' : str(paste_code) } # Name of the poster if paste_name is not None: argv['paste_name'] = str(paste_name) # Is the snippet private? if paste_private is not None: argv['paste_private'] = int(bool(int(paste_private))) # Expiration for the snippet if paste_expire_date is not None: paste_expire_date = str(paste_expire_date).strip().upper() argv['paste_expire_date'] = paste_expire_date # Syntax highlighting if paste_format is not None: paste_format = str(paste_format).strip().lower() argv['paste_format'] = paste_format # Make the request to the Pastebin API fd = urllib.urlopen(cls._api_url, urllib.urlencode(argv)) try: response = fd.read() finally: fd.close() del fd # Return the new snippet URL on success, raise exception on error if not response.startswith(cls._prefix_url): raise PastebinError(response) return response # Simple interface. submit = Pastebin.submit if __name__ == "__main__": import sys import optparse # Build the command line parser parser = optparse.OptionParser(usage = '%prog <file> [options]') parser.add_option("-n", "--name", action="store", type="string", metavar="NAME", help="author of the code to submit") parser.add_option("--private", action="store_true", help="the snippet is private") parser.add_option("--public", action="store_false", dest="private", help="the snippet is public") parser.add_option("-e", "--expire", action="store", type="string", metavar="TIME", help="expiration time: N (never), 10M (10 minutes), 1H (1 hour), 1D (1 day), 1M (1 month)") parser.add_option("-f", "--format", "--syntax", "--highlight", action="store", type="string", metavar="FORMAT", dest="format", help="syntax highlighting, use one of the following: " + \ ', '.join(Pastebin.paste_format)) # Parse the command line and submit each snippet options, args = parser.parse_args(sys.argv) args = args[1:] if not args: parser.print_help() for filename in args: data = open(filename, 'rb').read() url = Pastebin.submit(paste_code = data, paste_name = options.name, paste_private = options.private, paste_expire_date = options.expire, paste_format = options.format) print "%s --> %s" % (filename, url)