~ubuntu-branches/ubuntu/vivid/nautilus-pastebin/vivid

« back to all changes in this revision

Viewing changes to pastebin/core.py

  • Committer: Bazaar Package Importer
  • Author(s): Alessio Treglia
  • Date: 2009-10-02 14:46:39 UTC
  • Revision ID: james.westby@ubuntu.com-20091002144639-9qh33a65nbox0deq
Tags: upstream-0.2.1
Import upstream version 0.2.1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#!/usr/bin/python
 
2
# -*- coding: utf-8 -*-
 
3
# nautilus-pastebin - Nautilus extension to paste a file to a pastebin service
 
4
# Written by:
 
5
#    Alessio Treglia <quadrispro@ubuntu.com>
 
6
# Copyright (C) 2009, Alessio Treglia
 
7
#
 
8
# Part of this code has been taken from pastebinit script
 
9
# pastebinit was written by: 
 
10
#    Stéphane Graber <stgraber@stgraber.org>
 
11
#    Daniel Bartlett <dan@f-box.org>
 
12
#    David Paleino <d.paleino@gmail.com>
 
13
# URL: http://www.stgraber.org/download/projects/pastebin/
 
14
# Copyright (C) 2006-2009, Stéphane Graber, Daniel Bartlett, David Paleino
 
15
# Distributed under the terms of the GNU GPL-2 license
 
16
#
 
17
# This package is free software; you can redistribute it and/or modify
 
18
# it under the terms of the GNU General Public License as published by
 
19
# the Free Software Foundation; either version 2 of the License, or
 
20
# (at your option) any later version.
 
21
#
 
22
# This package is distributed in the hope that it will be useful,
 
23
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 
24
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
25
# GNU General Public License for more details.
 
26
#
 
27
# You should have received a copy of the GNU General Public License
 
28
# along with this package; if not, write to the Free Software
 
29
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
 
30
#
 
31
 
 
32
import urllib
 
33
import os, re
 
34
import mimetypes
 
35
 
 
36
from ConfigParser import ConfigParser
 
37
 
 
38
# Globals
 
39
GLOBALCONFIG_FILENAME = '/etc/nautilus-pastebin.conf'
 
40
USERCONFIG_FILENAME = os.path.expanduser('~/.config/nautilus-pastebin/nautilus-pastebin.conf')
 
41
 
 
42
class ConfigFileException(Exception):
 
43
    pass
 
44
 
 
45
# Custom urlopener to handle 401's
 
46
class pasteURLopener(urllib.FancyURLopener):
 
47
    """Do the HTTP requests."""
 
48
    def http_error_401(self, url, fp, errcode, errmsg, headers, data=None):
 
49
            return None
 
50
 
 
51
class GlobalConfigurationValidator(object):
 
52
    """Configuration wrapper """
 
53
    NEEDED_OPTS = ['pastebin']
 
54
    MAIN_SECTION = 'generals'
 
55
    
 
56
    def validate(self):
 
57
        glbl = dict(self.__config.items(GlobalConfigurationValidator.MAIN_SECTION))
 
58
        for k in glbl.keys():
 
59
            # Each needed field must be fill'd.
 
60
            if k in GlobalConfigurationValidator.NEEDED_OPTS and not glbl[k]:
 
61
                #raise ConfigFileException, "Missing required value for %s field!" % k
 
62
                return False
 
63
            if re.search('enable_.*', k): # In case of boolean value...
 
64
                # ...we should parse it well
 
65
                glbl[k] = self.__config.getboolean(GlobalConfigurationValidator.MAIN_SECTION, k)
 
66
        # Everything seems well-configured
 
67
        self.globals = glbl
 
68
        return True
 
69
 
 
70
    def getPastebinConfiguration(self):
 
71
        """Retrieve and returns the configuration related to the pastebin service."""
 
72
        pastebinConfiguration = None
 
73
        pastebin = self.globals['pastebin']
 
74
        return PastebinConfiguration(self.globals, dict(self.__config.items(pastebin)))
 
75
 
 
76
    def getAvailablePastebins(self):
 
77
        pastebins = self.__config.sections()
 
78
        pastebins.remove(GlobalConfigurationValidator.MAIN_SECTION)
 
79
        return pastebins
 
80
    
 
81
    def getConfigParser(self): return self.__config
 
82
    
 
83
    def __init__(self, files=[GLOBALCONFIG_FILENAME, USERCONFIG_FILENAME]):
 
84
        self.__config = ConfigParser()
 
85
        self.__config.read(files)
 
86
        self.globals = {}
 
87
 
 
88
class PastebinConfiguration(object):
 
89
    PARAMETERS = ["website",
 
90
        "validator",
 
91
        "content",
 
92
        "user",
 
93
        "jabberid",
 
94
        "version",
 
95
        "format",
 
96
        "parentid",
 
97
        "permatag",
 
98
        "title",
 
99
        "username",
 
100
        "password",
 
101
        "default_mime"]
 
102
 
 
103
    def __setDefaultParameters(self):
 
104
        for k in PastebinConfiguration.PARAMETERS:
 
105
            self.__dict__.setdefault(k,'')
 
106
            if k in self._optionsDict.keys():
 
107
                setattr(self, k, self._optionsDict[k])
 
108
 
 
109
    def __setGlobalParameters(self):
 
110
        for k in self._globalsDict.keys():
 
111
            setattr(self, k, self._globalsDict[k])
 
112
 
 
113
    def __getMappingByName(self, optname):
 
114
        map = {}
 
115
        if optname in self._optionsDict:
 
116
            exec(self._optionsDict[optname])
 
117
        return map
 
118
 
 
119
    def __init__(self, globalsDict, optionsDict):
 
120
        self._optionsDict = optionsDict
 
121
        self._globalsDict = globalsDict
 
122
        self.__setGlobalParameters()
 
123
        self.__setDefaultParameters()
 
124
        self.aliases = self.__getMappingByName('aliases')
 
125
        self.extras = self.__getMappingByName('extras')
 
126
        self.mimetypes = self.__getMappingByName('mimetypes')
 
127
        self.mimetypes.setdefault('text/plain', self._optionsDict['default_mime'])
 
128
 
 
129
    def setFormatByMimeType(self, mimetype):
 
130
        if mimetype in self.mimetypes.keys():
 
131
            self.format = self.mimetypes[mimetype]
 
132
        elif mimetype.split('/')[0] == 'text':
 
133
            self.format = self.mimetypes['text/plain']
 
134
        else:
 
135
            return False
 
136
        return True
 
137
    
 
138
    def __str__(self):
 
139
        s = 'Configuration:\n'
 
140
        s += "mimetypes = %s\n" % self.mimetypes.__str__()
 
141
        s += "aliases = %s" % self.aliases.__str__()
 
142
        s += "extras = %s" % self.extras.__str__()
 
143
        return s
 
144
 
 
145
    def setContent(self, pastefile):
 
146
        fp = open(pastefile)
 
147
        content = fp.read()
 
148
        fp.close()
 
149
        if not content:
 
150
            return False
 
151
        # OK, let's go...
 
152
        self.content = content
 
153
        self.title = os.path.split(pastefile)[-1]
 
154
        return True
 
155
 
 
156
class PastebinValidatorFactory(object):
 
157
    """Singleton factory which returns a validator object dinamically."""
 
158
    __instance = None
 
159
    class __impl(object):
 
160
        """Implementation of the class' methods"""
 
161
        def getValidator(self, pasteconf):
 
162
            validator = pasteconf.validator
 
163
            obj = None
 
164
            try:
 
165
                exec("obj = %sValidator(pasteconf)" % validator)
 
166
            except Exception, e:
 
167
                pass
 
168
            return obj
 
169
 
 
170
    def __getattr__(self, attr):
 
171
        return getattr(self.__instance, attr)
 
172
    def __setattr__(self, attr, value):
 
173
        return setattr(self.__instance, attr, value)
 
174
 
 
175
    def __init__(self):
 
176
        if PastebinValidatorFactory.__instance is None:
 
177
            PastebinValidatorFactory.__instance = PastebinValidatorFactory.__impl()
 
178
        self.__dict__['_PastebinValidatorFactory__instance'] = PastebinValidatorFactory.__instance
 
179
 
 
180
class GenericPastebinValidator(object):
 
181
    NOT_EMPTY_FIELDS = ['website', 'content', 'format', 'title']
 
182
 
 
183
    def checkAliases(self):
 
184
        return all(
 
185
            map(
 
186
                lambda x: x in self.conf.__dict__, self.conf.aliases.keys())
 
187
                )
 
188
 
 
189
    def checkExtras(self): return True
 
190
 
 
191
    def __init__(self, pastebinConfiguration):
 
192
        """Class constructor"""
 
193
        try:
 
194
            toAdd = getattr(cls, 'notEmptyFields')
 
195
            GenericPastebinValidator.NOT_EMPTY_FIELDS.extend(toAdd)
 
196
        except:
 
197
            pass
 
198
        self.conf = pastebinConfiguration
 
199
 
 
200
    def validate(self):
 
201
        """Do the validation of the configuration file."""
 
202
        if self.conf.user == '':
 
203
            self.conf.user = os.environ.get('USER')
 
204
        return self.checkNotEmpty() and self.checkAliases() and self.checkExtras()
 
205
 
 
206
    def checkNotEmpty(self):
 
207
        """Verify whether all the opts' keys are non-empty."""
 
208
        return all(map(lambda x: getattr(self.conf, x) != '', GenericPastebinValidator.NOT_EMPTY_FIELDS))
 
209
 
 
210
    def getParameters(self):
 
211
        params = {}
 
212
        # Set the aliases
 
213
        for k in self.conf.aliases.keys():
 
214
            for v in self.conf.aliases[k]:
 
215
                params[v] = getattr(self.conf, k)
 
216
        for k in self.conf.extras.keys():
 
217
            params[k] = self.conf.extras[k]
 
218
        return params
 
219
    
 
220
    def updateParametersAfterSending(self): pass
 
221
 
 
222
class PasteyNetValidator(GenericPastebinValidator):
 
223
 
 
224
    def parentFixup(self, website, parentid):
 
225
        if parentid == "":
 
226
            return ""
 
227
        url_opener = pasteURLopener()
 
228
        page = url_opener.open(website + '/' + parentid, None)
 
229
        matches = re.split('<input.*?name="parent".*?value="(.*?)"', page.read())
 
230
        if len(matches) <= 1 or re.match(parentid, matches[1]) == None:
 
231
            # The obfuscated version didn't begin with the partial version,
 
232
            # or unable to find the obfuscated version for some reason!
 
233
            # Create a paste with no parent (should we throw, instead?)
 
234
            return ""
 
235
        return matches[1]
 
236
 
 
237
    def getParameters(self):
 
238
        params = GenericPastebinValidator.getParameters(self)
 
239
        params['parent'] = self.parentFixup(self.conf.website, self.conf.parentid)
 
240
        return params
 
241
 
 
242
class Paster(object):
 
243
    def __init__(self, pasteconf):
 
244
        self.pasteconf = pasteconf
 
245
 
 
246
    def paste(self):
 
247
        validator = PastebinValidatorFactory().getValidator(self.pasteconf)
 
248
        pasteurl = None
 
249
        
 
250
        if (not validator) or (not validator.validate()):
 
251
            return pasteurl
 
252
 
 
253
        website = self.pasteconf.website
 
254
        params = validator.getParameters()
 
255
 
 
256
        if not re.search(".*/", website):
 
257
            website += "/"
 
258
 
 
259
        reLink=None
 
260
        tmp_page=""
 
261
        if params.__contains__("page"):
 
262
            website+=params['page']
 
263
            tmp_page=params['page']
 
264
            params.__delitem__("page")
 
265
        if params.__contains__("regexp"):
 
266
            reLink=params['regexp']
 
267
            params.__delitem__("regexp")
 
268
        params = urllib.urlencode(params) #Convert to a format usable with the HTML POST
 
269
 
 
270
        try:
 
271
            url_opener = pasteURLopener()
 
272
            page = url_opener.open(website, params) #Send the informations and be redirected to the final page
 
273
            summary = 'File pasted to: '
 
274
            URLmarkup = '<a href="%(pasteurl)s">%(pasteurl)s</a>'
 
275
            if reLink: #Check if we have to apply a regexp
 
276
                if website.count(tmp_page) > 1:
 
277
                    website = website.rstrip(tmp_page)
 
278
                else:
 
279
                    website = website.replace(tmp_page, "")
 
280
                pasteurl = website + "/" + re.split(reLink, page.read())[1]
 
281
            else:
 
282
                pasteurl = page.url
 
283
            message = URLmarkup % { 'pasteurl': pasteurl }
 
284
 
 
285
        except Exception, value:
 
286
            pasteurl = None
 
287
        return pasteurl
 
288