diff options
| author | Kali Kaneko <kali@leap.se> | 2014-02-26 10:42:38 -0400 | 
|---|---|---|
| committer | Kali Kaneko <kali@leap.se> | 2014-02-26 10:42:38 -0400 | 
| commit | f0346b77185dc353d6ac65308189fbe236ce2b44 (patch) | |
| tree | c11b203beb2a8e813945cc4c6dfadc184dd8e6c0 /src | |
| parent | 3e5e020e1e23f83cffa0a3579f0755401f18a9e7 (diff) | |
| parent | 6650529db2f001718bb79eab34aee4d4830eb346 (diff) | |
Merge remote-tracking branch 'ivan-github/feature/add-pastebin-support' into develop
Diffstat (limited to 'src')
| -rw-r--r-- | src/leap/bitmask/gui/loggerwindow.py | 83 | ||||
| -rw-r--r-- | src/leap/bitmask/gui/ui/loggerwindow.ui | 15 | ||||
| -rw-r--r-- | src/leap/bitmask/util/constants.py | 1 | ||||
| -rwxr-xr-x | src/leap/bitmask/util/pastebin.py | 814 | 
4 files changed, 911 insertions, 2 deletions
| diff --git a/src/leap/bitmask/gui/loggerwindow.py b/src/leap/bitmask/gui/loggerwindow.py index 6ef58558..9b6cef91 100644 --- a/src/leap/bitmask/gui/loggerwindow.py +++ b/src/leap/bitmask/gui/loggerwindow.py @@ -22,10 +22,13 @@ import logging  import cgi  from PySide import QtGui +from twisted.internet import threads  from ui_loggerwindow import Ui_LoggerWindow +from leap.bitmask.util.constants import PASTEBIN_API_DEV_KEY  from leap.bitmask.util.leap_log_handler import LeapLogHandler +from leap.bitmask.util.pastebin import PastebinAPI, PastebinError  from leap.common.check import leap_assert, leap_assert_type  logger = logging.getLogger(__name__) @@ -42,6 +45,9 @@ class LoggerWindow(QtGui.QDialog):          :param handler: Custom handler that supports history and signal.          :type handler: LeapLogHandler.          """ +        from twisted.internet import reactor +        self.reactor = reactor +          QtGui.QDialog.__init__(self)          leap_assert(handler, "We need a handler for the logger window")          leap_assert_type(handler, LeapLogHandler) @@ -59,8 +65,10 @@ class LoggerWindow(QtGui.QDialog):          self.ui.btnCritical.toggled.connect(self._load_history)          self.ui.leFilterBy.textEdited.connect(self._filter_by)          self.ui.cbCaseInsensitive.stateChanged.connect(self._load_history) +        self.ui.btnPastebin.clicked.connect(self._pastebin_this)          self._current_filter = "" +        self._current_history = ""          # Load logging history and connect logger with the widget          self._logging_handler = handler @@ -116,8 +124,13 @@ class LoggerWindow(QtGui.QDialog):          self._set_logs_to_display()          self.ui.txtLogHistory.clear()          history = self._logging_handler.log_history +        current_history = []          for line in history:              self._add_log_line(line) +            message = cgi.escape(line[LeapLogHandler.MESSAGE_KEY]) +            current_history.append(message) + +        self._current_history = "\n".join(current_history)      def _set_logs_to_display(self):          """ @@ -164,3 +177,73 @@ class LoggerWindow(QtGui.QDialog):                  logger.error("Error saving log file: %r" % (e, ))          else:              logger.debug('Log not saved!') + +    def _set_pastebin_sending(self, sending): +        """ +        Define the status of the pastebin button. +        Change the text and enable/disable according to the current action. + +        :param sending: if we are sending to pastebin or not. +        :type sending: bool +        """ +        if sending: +            self.ui.btnPastebin.setText(self.tr("Sending to pastebin...")) +            self.ui.btnPastebin.setEnabled(False) +        else: +            self.ui.btnPastebin.setText(self.tr("Send to Pastebin.com")) +            self.ui.btnPastebin.setEnabled(True) + +    def _pastebin_this(self): +        """ +        Send the current log history to pastebin.com and gives the user a link +        to see it. +        """ +        def do_pastebin(): +            """ +            Send content to pastebin and return the link. +            """ +            content = self._current_history +            pb = PastebinAPI() +            link = pb.paste(PASTEBIN_API_DEV_KEY, content, +                            paste_name="Bitmask log", +                            paste_expire_date='1W') + +            # convert to 'raw' link +            link = "http://pastebin.com/raw.php?i=" + link.split('/')[-1] + +            return link + +        def pastebin_ok(link): +            """ +            Callback handler for `do_pastebin`. + +            :param link: the recently created pastebin link. +            :type link: str +            """ +            msg = self.tr("Your pastebin link <a href='{0}'>{0}</a>") +            msg = msg.format(link) +            logger.debug(msg) +            show_info = lambda: QtGui.QMessageBox.information( +                self, self.tr("Pastebin OK"), msg) +            self._set_pastebin_sending(False) +            self.reactor.callLater(0, show_info) + +        def pastebin_err(failure): +            """ +            Errback handler for `do_pastebin`. + +            :param failure: the failure that triggered the errback. +            :type failure: twisted.python.failure.Failure +            """ +            logger.error(repr(failure)) +            msg = self.tr("Sending logs to Pastebin failed!") +            show_err = lambda: QtGui.QMessageBox.error( +                self, self.tr("Pastebin Error"), msg) +            self._set_pastebin_sending(False) +            self.reactor.callLater(0, show_err) +            failure.trap(PastebinError) + +        self._set_pastebin_sending(True) +        d = threads.deferToThread(do_pastebin) +        d.addCallback(pastebin_ok) +        d.addErrback(pastebin_err) diff --git a/src/leap/bitmask/gui/ui/loggerwindow.ui b/src/leap/bitmask/gui/ui/loggerwindow.ui index 3de786f7..b19ed91a 100644 --- a/src/leap/bitmask/gui/ui/loggerwindow.ui +++ b/src/leap/bitmask/gui/ui/loggerwindow.ui @@ -6,8 +6,8 @@     <rect>      <x>0</x>      <y>0</y> -    <width>648</width> -    <height>469</height> +    <width>769</width> +    <height>464</height>     </rect>    </property>    <property name="windowTitle"> @@ -154,6 +154,17 @@         </property>        </widget>       </item> +     <item> +      <widget class="QPushButton" name="btnPastebin"> +       <property name="text"> +        <string>Send to Pastebin.com</string> +       </property> +       <property name="icon"> +        <iconset resource="../../../../../data/resources/loggerwindow.qrc"> +         <normaloff>:/images/pastebin.png</normaloff>:/images/pastebin.png</iconset> +       </property> +      </widget> +     </item>      </layout>     </item>    </layout> diff --git a/src/leap/bitmask/util/constants.py b/src/leap/bitmask/util/constants.py index e6a6bdce..e7e72cc4 100644 --- a/src/leap/bitmask/util/constants.py +++ b/src/leap/bitmask/util/constants.py @@ -17,3 +17,4 @@  SIGNUP_TIMEOUT = 5  REQUEST_TIMEOUT = 15 +PASTEBIN_API_DEV_KEY = "09563100642af6085d641f749a1922b4" diff --git a/src/leap/bitmask/util/pastebin.py b/src/leap/bitmask/util/pastebin.py new file mode 100755 index 00000000..21b8a0b7 --- /dev/null +++ b/src/leap/bitmask/util/pastebin.py @@ -0,0 +1,814 @@ +#!/usr/bin/env python
 +
 +#############################################################################
 +#    Pastebin.py - Python 3.2 Pastebin API.
 +#    Copyright (C) 2012  Ian Havelock
 +#
 +#    This program is free software: you can redistribute it and/or modify
 +#    it under the terms of the GNU General Public License as published by
 +#    the Free Software Foundation, either version 3 of the License, or
 +#    (at your option) any later version.
 +#
 +#    This program is distributed in the hope that it will be useful,
 +#    but WITHOUT ANY WARRANTY; without even the implied warranty of
 +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 +#    GNU General Public License for more details.
 +#
 +#    You should have received a copy of the GNU General Public License
 +#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
 +#
 +
 +#############################################################################
 +
 +# This software is a derivative work of:
 +# http://winappdbg.sourceforge.net/blog/pastebin.py
 +
 +#############################################################################
 +
 +
 +__ALL__ = ['delete_paste', 'user_details', 'trending', 'pastes_by_user',
 +           'generate_user_key', 'legacy_paste', 'paste', '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 PastebinAPI(object):
 +    """Pastebin API interaction object.
 +
 +    Public functions:
 +
 +    paste -- Pastes a user-specified file or string using the new API-key POST
 +    method.
 +
 +    legacy_paste -- Pastes a user-specified file or string using the old
 +    anonymous POST method.
 +
 +    generate_user_key -- Generates a session-key that is required for other
 +    functions.
 +
 +    pastes_by_user -- Returns all public pastes submitted by the specified
 +    login credentials.
 +
 +    trending -- Returns the top trending paste.
 +
 +    user_details -- Returns details about the user for the specified API user
 +    key.
 +
 +    delete_paste -- Adds two numbers together and returns the result."""
 +
 +    # String to determine bad API requests
 +    _bad_request = 'Bad API request'
 +
 +    # Base domain name
 +    _base_domain = 'pastebin.com'
 +
 +    # Valid Pastebin URLs begin with this string (kinda obvious)
 +    _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 LEGACY POST API
 +    _legacy_api_url = 'http://%s/api_public.php' % _base_domain
 +
 +    # URL to the POST API
 +    _api_url = 'http://%s/api/api_post.php' % _base_domain
 +
 +    # URL to the login POST API
 +    _api_login_url = 'http://%s/api/api_login.php' % _base_domain
 +
 +    # Valid paste_expire_date values: Never, 10 minutes, 1 Hour, 1 Day, 1 Month
 +    paste_expire_date = ('N', '10M', '1H', '1D', '1M')
 +
 +    # Valid paste_expire_date values (0 = public, 1 = unlisted, 2 = private)
 +    paste_private = ('public', 'unlisted', 'private')
 +
 +    # 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
 +    )
 +
 +    def __init__(self):
 +        pass
 +
 +    def delete_paste(self, api_dev_key, api_user_key, api_paste_key):
 +        """Delete the paste specified by the api_paste_key.
 +
 +        Usage Example::
 +        from pastebin import PastebinAPI
 +        x = PastebinAPI()
 +        paste_to_delete = x.delete_paste(
 +            '453a994e0e2f1efae07f8759e59e075b',
 +            'c57a18e6c0ae228cd4bd16fe36da381a',
 +            'WkgcTFtv')
 +        print paste_to_delete
 +        Paste Removed
 +
 +
 +        @type   api_dev_key: string
 +        @param  api_dev_key: The API Developer Key of a registered
 +                             U{http://pastebin.com} account.
 +
 +        @type   api_user_key: string
 +        @param  api_user_key: The API User Key of a U{http://pastebin.com}
 +                              registered user.
 +
 +        @type   api_paste_key: string
 +        @param  api_paste_key: The Paste Key of the paste to be deleted
 +                               (string after final / in
 +                               U{http://pastebin.com} URL).
 +
 +        @rtype: string
 +        @returns: A successful deletion returns 'Paste Removed'.
 +        """
 +
 +        # Valid api developer key
 +        argv = {'api_dev_key': str(api_dev_key)}
 +
 +        # Requires pre-registered account
 +        if api_user_key is not None:
 +            argv['api_user_key'] = str(api_user_key)
 +
 +        # Key of the paste to be deleted.
 +        if api_paste_key is not None:
 +            argv['api_paste_key'] = str(api_paste_key)
 +
 +        # Valid API option - 'user_details' in this instance
 +        argv['api_option'] = str('delete')
 +
 +        # lets try to read the URL that we've just built.
 +        request_string = urllib.urlopen(self._api_url, urllib.urlencode(argv))
 +        response = request_string.read()
 +
 +        return response
 +
 +    def user_details(self, api_dev_key, api_user_key):
 +        """Return user details of the user specified by the api_user_key.
 +
 +
 +        Usage Example::
 +            from pastebin import PastebinAPI
 +            x = PastebinAPI()
 +            details = x.user_details('453a994e0e2f1efae07f8759e59e075b', 'c57a18e6c0ae228cd4bd16fe36da381a')
 +            print details
 +            <user>
 +            <user_name>MonkeyPuzzle</user_name>
 +            <user_format_short>python</user_format_short>
 +            <user_expiration>N</user_expiration>
 +            <user_avatar_url>http://pastebin.com/i/guest.gif</user_avatar_url>
 +            <user_private>0</user_private>
 +            <user_website></user_website>
 +            <user_email>user@email.com</user_email>
 +            <user_location></user_location>
 +            <user_account_type>0</user_account_type>
 +            </user>
 +
 +
 +        @type   api_dev_key: string
 +        @param  api_dev_key: The API Developer Key of a registered
 +                             U{http://pastebin.com} account.
 +
 +        @type   api_user_key: string
 +        @param  api_user_key: The API User Key of a U{http://pastebin.com}
 +                              registered user.
 +
 +        @rtype: string
 +        @returns: Returns an XML string containing user information.
 +        """
 +
 +        # Valid api developer key
 +        argv = {'api_dev_key': str(api_dev_key)}
 +
 +        # Requires pre-registered account to generate an api_user_key
 +        # (see generate_user_key)
 +        if api_user_key is not None:
 +            argv['api_user_key'] = str(api_user_key)
 +
 +        # Valid API option - 'user_details' in this instance
 +        argv['api_option'] = str('userdetails')
 +
 +        # lets try to read the URL that we've just built.
 +        request_string = urllib.urlopen(self._api_url, urllib.urlencode(argv))
 +        response = request_string.read()
 +
 +        # do some basic error checking here so we can gracefully handle any
 +        # errors we are likely to encounter
 +        if response.startswith(self._bad_request):
 +            raise PastebinError(response)
 +
 +        elif not response.startswith('<user>'):
 +            raise PastebinError(response)
 +
 +        return response
 +
 +    def trending(self, api_dev_key):
 +        """Returns the top trending paste details.
 +
 +
 +        Usage Example::
 +            from pastebin import PastebinAPI
 +            x = PastebinAPI()
 +            details = x.trending('453a994e0e2f1efae07f8759e59e075b')
 +            print details
 +            <paste>
 +            <paste_key>jjMRFDH6</paste_key>
 +            <paste_date>1333230838</paste_date>
 +            <paste_title></paste_title>
 +            <paste_size>6416</paste_size>
 +            <paste_expire_date>0</paste_expire_date>
 +            <paste_private>0</paste_private>
 +            <paste_format_long>None</paste_format_long>
 +            <paste_format_short>text</paste_format_short>
 +            <paste_url>http://pastebin.com/jjMRFDH6</paste_url>
 +            <paste_hits>6384</paste_hits>
 +            </paste>
 +
 +        Note: Returns multiple trending pastes, not just 1.
 +
 +
 +        @type   api_dev_key: string
 +        @param  api_dev_key: The API Developer Key of a registered
 +                             U{http://pastebin.com} account.
 +
 +
 +        @rtype:  string
 +        @return: Returns the string (XML formatted) containing the top
 +                 trending pastes.
 +        """
 +
 +        # Valid api developer key
 +        argv = {'api_dev_key': str(api_dev_key), 'api_option': str('trends')}
 +
 +        # Valid API option - 'trends' is returns trending pastes
 +
 +        # lets try to read the URL that we've just built.
 +        request_string = urllib.urlopen(self._api_url, urllib.urlencode(argv))
 +        response = request_string.read()
 +
 +        # do some basic error checking here so we can gracefully handle any
 +        # errors we are likely to encounter
 +        if response.startswith(self._bad_request):
 +            raise PastebinError(response)
 +
 +        elif not response.startswith('<paste>'):
 +            raise PastebinError(response)
 +
 +        return response
 +
 +    def pastes_by_user(self, api_dev_key, api_user_key, results_limit=None):
 +        """Returns all pastes for the provided api_user_key.
 +
 +
 +        Usage Example::
 +            from pastebin import PastebinAPI
 +            x = PastebinAPI()
 +            details = x.user_details('453a994e0e2f1efae07f8759e59e075b',
 +                                     'c57a18e6c0ae228cd4bd16fe36da381a',
 +                                     100)
 +            print details
 +            <paste>
 +            <paste_key>DLiSspYT</paste_key>
 +            <paste_date>1332714730</paste_date>
 +            <paste_title>Pastebin.py - Python 3.2 Pastebin.com API</paste_title>
 +            <paste_size>25300</paste_size>
 +            <paste_expire_date>0</paste_expire_date>
 +            <paste_private>0</paste_private>
 +            <paste_format_long>Python</paste_format_long>
 +            <paste_format_short>python</paste_format_short>
 +            <paste_url>http://pastebin.com/DLiSspYT</paste_url>
 +            <paste_hits>70</paste_hits>
 +            </paste>
 +
 +        Note: Returns multiple pastes, not just 1.
 +
 +
 +        @type   api_dev_key: string
 +        @param  api_dev_key: The API Developer Key of a registered
 +                             U{http://pastebin.com} account.
 +
 +        @type   api_user_key: string
 +        @param  api_user_key: The API User Key of a U{http://pastebin.com}
 +                              registered user.
 +
 +        @type   results_limit: number
 +        @param  results_limit: The number of pastes to return between 1 - 1000.
 +
 +        @rtype: string
 +        @returns: Returns an XML string containing number of specified pastes
 +                  by user.
 +        """
 +
 +        # Valid api developer key
 +        argv = {'api_dev_key': str(api_dev_key)}
 +
 +        # Requires pre-registered account
 +        if api_user_key is not None:
 +            argv['api_user_key'] = str(api_user_key)
 +
 +        # Number of results to return - between 1 & 1000, default = 50
 +        if results_limit is None:
 +            argv['api_results_limit'] = 50
 +
 +        if results_limit is not None:
 +            if results_limit < 1:
 +                argv['api_results_limit'] = 50
 +            elif results_limit > 1000:
 +                argv['api_results_limit'] = 1000
 +            else:
 +                argv['api_results_limit'] = int(results_limit)
 +
 +        # Valid API option - 'paste' is default for new paste
 +        argv['api_option'] = str('list')
 +
 +        # lets try to read the URL that we've just built.
 +        request_string = urllib.urlopen(self._api_url, urllib.urlencode(argv))
 +        response = request_string.read()
 +
 +        # do some basic error checking here so we can gracefully handle any
 +        # errors we are likely to encounter
 +        if response.startswith(self._bad_request):
 +            raise PastebinError(response)
 +
 +        elif not response.startswith('<paste>'):
 +            raise PastebinError(response)
 +
 +        return response
 +
 +    def generate_user_key(self, api_dev_key, username, password):
 +        """Generate a user session key - needed for other functions.
 +
 +
 +        Usage Example::
 +            from pastebin import PastebinAPI
 +            x = PastebinAPI()
 +            my_key = x.generate_user_key(
 +                '453a994e0e2f1efae07f8759e59e075b',
 +                'MonkeyPuzzle',
 +                '12345678')
 +            print my_key
 +            c57a18e6c0ae228cd4bd16fe36da381a
 +
 +
 +        @type   api_dev_key: string
 +        @param  api_dev_key: The API Developer Key of a registered
 +                             U{http://pastebin.com} account.
 +
 +        @type   username: string
 +        @param  username: The username of a registered U{http://pastebin.com}
 +                          account.
 +
 +        @type   password: string
 +        @param  password: The password of a registered U{http://pastebin.com}
 +                          account.
 +
 +        @rtype: string
 +        @returns: Session key (api_user_key) to allow authenticated
 +                  interaction to the API.
 +
 +        """
 +        # Valid api developer key
 +        argv = {'api_dev_key': str(api_dev_key)}
 +
 +        # Requires pre-registered pastebin account
 +        if username is not None:
 +            argv['api_user_name'] = str(username)
 +
 +        # Requires pre-registered pastebin account
 +        if password is not None:
 +            argv['api_user_password'] = str(password)
 +
 +        # lets try to read the URL that we've just built.
 +        data = urllib.urlencode(argv)
 +        request_string = urllib.urlopen(self._api_login_url, data)
 +        response = request_string.read()
 +
 +        # do some basic error checking here so we can gracefully handle
 +        # any errors we are likely to encounter
 +        if response.startswith(self._bad_request):
 +            raise PastebinError(response)
 +
 +        return response
 +
 +    def paste(self, api_dev_key, api_paste_code,
 +              api_user_key=None, paste_name=None, paste_format=None,
 +              paste_private=None, paste_expire_date=None):
 +
 +        """Submit a code snippet to Pastebin using the new API.
 +
 +
 +        Usage Example::
 +            from pastebin import PastebinAPI
 +            x = PastebinAPI()
 +            url = x.paste(
 +                '453a994e0e2f1efae07f8759e59e075b' ,
 +                'Snippet of code to paste goes here',
 +                paste_name = 'title of paste',
 +                api_user_key = 'c57a18e6c0ae228cd4bd16fe36da381a',
 +                paste_format = 'python',
 +                paste_private = 'unlisted',
 +                paste_expire_date = '10M')
 +            print url
 +            http://pastebin.com/tawPUgqY
 +
 +
 +        @type   api_dev_key: string
 +        @param  api_dev_key: The API Developer Key of a registered
 +                             U{http://pastebin.com} account.
 +
 +        @type   api_paste_code: string
 +        @param  api_paste_code: The file or string to paste to body of the
 +                                U{http://pastebin.com} paste.
 +
 +        @type   api_user_key: string
 +        @param  api_user_key: The API User Key of a U{http://pastebin.com}
 +                              registered user.
 +                              If none specified, paste is made as a guest.
 +
 +        @type   paste_name: string
 +        @param  paste_name: (Optional) Title of the paste.
 +            Default is to paste anonymously.
 +
 +        @type  paste_format: string
 +        @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).
 +
 +        @type  paste_private: string
 +        @param paste_private: (Optional) C{'public'} if the paste is public
 +            (visible by everyone), C{'unlisted'} if it's public but not
 +            searchable. C{'private'} if the paste is private and not
 +            searchable or indexed.
 +            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{PastebinAPI.paste_expire_date} class
 +            member.
 +            If not provided, the paste never expires.
 +
 +        @rtype:  string
 +        @return: Returns the URL to the newly created paste.
 +        """
 +
 +        # Valid api developer key
 +        argv = {'api_dev_key': str(api_dev_key)}
 +
 +        # Code snippet to submit
 +        if api_paste_code is not None:
 +            argv['api_paste_code'] = str(api_paste_code)
 +
 +        # Valid API option - 'paste' is default for new paste
 +        argv['api_option'] = str('paste')
 +
 +        # API User Key
 +        if api_user_key is not None:
 +            argv['api_user_key'] = str(api_user_key)
 +        elif api_user_key is None:
 +            argv['api_user_key'] = str('')
 +
 +        # Name of the poster
 +        if paste_name is not None:
 +            argv['api_paste_name'] = str(paste_name)
 +
 +        # Syntax highlighting
 +        if paste_format is not None:
 +            paste_format = str(paste_format).strip().lower()
 +            argv['api_paste_format'] = paste_format
 +
 +        # Is the snippet private?
 +        if paste_private is not None:
 +            if paste_private == 'public':
 +                argv['api_paste_private'] = int(0)
 +            elif paste_private == 'unlisted':
 +                argv['api_paste_private'] = int(1)
 +            elif paste_private == 'private':
 +                argv['api_paste_private'] = int(2)
 +
 +        # Expiration for the snippet
 +        if paste_expire_date is not None:
 +            paste_expire_date = str(paste_expire_date).strip().upper()
 +            argv['api_paste_expire_date'] = paste_expire_date
 +
 +        # lets try to read the URL that we've just built.
 +        request_string = urllib.urlopen(self._api_url, urllib.urlencode(argv))
 +        response = request_string.read()
 +
 +        # do some basic error checking here so we can gracefully handle any
 +        # errors we are likely to encounter
 +        if response.startswith(self._bad_request):
 +            raise PastebinError(response)
 +        elif not response.startswith(self._prefix_url):
 +            raise PastebinError(response)
 +
 +        return response
 +
 +    def legacy_paste(self, paste_code,
 +                     paste_name=None, paste_private=None,
 +                     paste_expire_date=None, paste_format=None):
 +        """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.
 +
 +
 +        Usage Example::
 +            from pastebin import PastebinAPI
 +            x = PastebinAPI()
 +            url = x.legacy_paste('Snippet of code to paste goes here',
 +                                paste_name = 'title of paste',
 +                                paste_private = 'unlisted',
 +                                paste_expire_date = '10M',
 +                                paste_format = 'python')
 +            print url
 +            http://pastebin.com/tawPUgqY
 +
 +
 +        @type   paste_code: string
 +        @param  paste_code: The file or string to paste to body of the
 +                            U{http://pastebin.com} paste.
 +
 +        @type   paste_name: string
 +        @param  paste_name: (Optional) Title of the paste.
 +            Default is to paste with no title.
 +
 +        @type   paste_private: string
 +        @param  paste_private: (Optional) C{'public'} if the paste is public
 +            (visible by everyone), C{'unlisted'} if it's public but not
 +            searchable. C{'private'} if the paste is private and not
 +            searchable or indexed.
 +            The Pastebin FAQ (U{http://pastebin.com/faq}) claims
 +            private pastes are not indexed by search engines (aka Google).
 +
 +        @type   paste_expire_date: string
 +        @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{PastebinAPI.paste_expire_date} class
 +            member.
 +            If not provided, the paste never expires.
 +
 +        @type   paste_format: string
 +        @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:  string
 +        @return: Returns the URL to the newly created paste.
 +        """
 +
 +        # 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
 +
 +        # lets try to read the URL that we've just built.
 +        data = urllib.urlencode(argv)
 +        request_string = urllib.urlopen(self._legacy_api_url, data)
 +        response = request_string.read()
 +
 +        # do some basic error checking here so we can gracefully handle any
 +        # errors we are likely to encounter
 +        if response.startswith(self._bad_request):
 +            raise PastebinError(response)
 +        elif not response.startswith(self._prefix_url):
 +            raise PastebinError(response)
 +
 +        return response
 +
 +
 +######################################################
 +
 +delete_paste = PastebinAPI.delete_paste
 +user_details = PastebinAPI.user_details
 +trending = PastebinAPI.trending
 +pastes_by_user = PastebinAPI.pastes_by_user
 +generate_user_key = PastebinAPI.generate_user_key
 +legacy_paste = PastebinAPI.legacy_paste
 +paste = PastebinAPI.paste
 | 
