#!/usr/bin/env python # -*- coding: utf-8 -*- # nautilus-pastebin - Nautilus extension to paste a file to a pastebin service # Written by: # Alessio Treglia # Copyright (C) 2009, Alessio Treglia # # Part of this code has been taken from pastebinit script # pastebinit was written by: # Stéphane Graber # Daniel Bartlett # David Paleino # URL: http://www.stgraber.org/download/projects/pastebin/ # Copyright (C) 2006-2009, Stéphane Graber, Daniel Bartlett, David Paleino # Distributed under the terms of the GNU GPL-2 license # # This package 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 2 of the License, or # (at your option) any later version. # # This package 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 package; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA # import urllib import gtk import nautilus import pynotify import os, sys, re, sys, mimetypes import gettext from ConfigParser import ConfigParser gettext.install("nautilus-pastebin") # Globals NAME_APP = "nautilus-pastebin" CONFIG_FILENAME = 'nautilus-pastebin.conf' USERCONFIG_RELPATH = '.config/nautilus-pastebin' PATH_APP = '/usr/share/nautilus-pastebin' LOGGING = True class ConfigFileException(Exception): pass pynotify.init("Nautilus pastebin extension") def getConfigurationFilename(): homedir = os.environ.get('HOME') file_conf = '' try: file_conf = os.path.join(homedir, USERCONFIG_RELPATH, CONFIG_FILENAME) os.stat(file_conf) except: file_conf = os.path.join('/etc', CONFIG_FILENAME) return file_conf def getPluginsPath(): homedir = os.environ.get('HOME') plugins_dirs = [] tmp = os.path.join(homedir, USERCONFIG_RELPATH) if os.path.isdir(tmp): plugins_dirs.append(tmp) tmp = os.path.join(PATH_APP, 'plugins') if os.path.isdir(tmp): plugins_dirs.append(tmp) return plugins_dirs def log(message): if LOGGING: if sys.version.split()[0] < '3': print message else: print (message) # Custom urlopener to handle 401's class pasteURLopener(urllib.FancyURLopener): def http_error_401(self, url, fp, errcode, errmsg, headers, data=None): return None class ConfigurationValidator(object): """Configuration wrapper """ NEEDED_OPTS = ['pastebin'] def validate(self): log (_("Validating configuration file...")) conf = {} opts = self.__config.options('generals') # Each needed field must be fill'd. if not set(ConfigurationValidator.NEEDED_OPTS).issubset(set(opts)): raise ConfigFileException, _("Missing some required values in the configuration file.") for k in opts: conf[k] = self.__config.get('generals', k) if k in ConfigurationValidator.NEEDED_OPTS and conf[k] == '': raise ConfigFileException, _("Missing some required values in the configuration file.") # Everything seems well-configured for k,v in conf.items(): setattr(self,k,v) return True def getPastebinConfiguration(self): """Retrieve and returns the configuration related to the pastebin service.""" pastebinConfiguration = None if self.__config.has_section(self.pastebin): pastebinConfiguration = PastebinConfiguration( dict(self.__config.items(self.pastebin)) ) return pastebinConfiguration def reloadConfiguration(self): """Reload the configuration file""" log (_("Reloading configuration...")) self.__config.read(self.filename) def __init__(self, filename='nautilus-pastebin.conf'): log (_("Initializing global configuration validator...")) self.filename = filename self.__config = ConfigParser() self.__config.read(filename) class PastebinConfiguration(object): PARAMETERS = ["website", "content", "user", "jabberid", "version", "format", "parentpid", "permatag", "title", "username", "password"] def __init__(self, optionsDict): log (_("Initializing pastebin configuration...")) # Initialize all parameters for k in PastebinConfiguration.PARAMETERS: setattr(self,k,'') # Read the configuration and set the parameters for k,v in optionsDict.items(): setattr(self,k,v) # Initializing formatMap... formatMap = dict(map(lambda k: (k,''), filter(lambda x: x.startswith('text'), mimetypes.types_map.values()))) for i in formatMap.keys(): # Set 'text' as default format formatMap[i] = 'text' # Read the custom types list from the configuration exec(optionsDict['mimetypes']) self.mimetypes = formatMap def setFormatByMimeType(self, mimetype): try: self.format = self.mimetypes[mimetype] except KeyError: return False # unsupported mimetype return True def __str__(self): s = 'Configuration:\n' for k in PastebinConfiguration.PARAMETERS: s += "%(k)s = %(v)s\n" % {'k' : k, 'v': getattr(self, k)} s += "mimetypes = %s" % self.mimetypes.__str__() return s class PastebinValidatorFactory(object): """Singleton factory which returns a validator object dinamically.""" __instance = None class __impl(object): """Implementation of the class' methods""" def getValidator(self, pastebinConfiguration): website = pastebinConfiguration.website log (_("Looking for a validator: %s") %website) if (re.search("http://((([a-zA-Z0-9\-_\.]*)(pastebin\.com)))", website) and not website == "http://www.pastebin.com") or website == "http://pastebin.mozilla.org": return PastebinComValidator(pastebinConfiguration) elif re.search("http://((([a-zA-Z0-9\-_\.]*)(pastebin\.ca)))", website): return PastebinCaValidator(pastebinConfiguration) elif website == "http://rafb.net": return RafbNetValidator(pastebinConfiguration) elif website == "http://stikked.com": return StikkedComValidator(pastebinConfiguration) elif website == "http://slexy.org": return SlexyOrgValidator(pastebinConfiguration) elif website == "http://fpaste.org": return FpasteValidator(pastebinConfiguration) elif website == "http://paste2.org": return Paste2OrgValidator(pastebinConfiguration) elif re.search("http://((([a-zA-Z0-9\-_\.]*)(pastey\.net)))", website): return PasteyNetValidator(pastebinConfiguration) elif website == "http://yourpaste.net": return YourpasteNetValidator(pastebinConfiguration) elif website == "http://gist.github.com": return GistGithubComValidator(pastebinConfiguration) elif website == "http://paste.ubuntu.com": return PasteUbuntuComValidator(pastebinConfiguration) elif website == "http://paste.debian.net": return PasteDebianNetValidator(pastebinConfiguration) else: return None # Service has not been recognized def __init__(self): if PastebinValidatorFactory.__instance is None: PastebinValidatorFactory.__instance = PastebinValidatorFactory.__impl() self.__dict__['_PastebinValidatorFactory__instance'] = PastebinValidatorFactory.__instance def __getattr__(self, attr): return getattr(self.__instance, attr) def __setattr__(self, attr, value): return setattr(self.__instance, attr, value) class GenericPastebinValidator(object): NOT_EMPTY_FIELDS = ['website', 'content'] def __init__(self, pastebinConfiguration): if not self.__class__.__name__ == 'GenericPastebinValidator': self.conf = pastebinConfiguration else: raise NotImplementedError def validate(self): if not self.__class__.__name__ == 'GenericPastebinValidator': if not self.checkNotEmpty(['content', 'website']): return False if self.conf.user == '': self.conf.user = os.environ.get('USER') return True else: raise NotImplementedError def checkNotEmpty(self, opts): if not self.__class__.__name__ == 'GenericPastebinValidator': try: for i in GenericPastebinValidator.NOT_EMPTY_FIELDS: if getattr(self.conf, i) == '': raise Exception except: return False return True else: raise NotImplementedError def getParameters(self): raise NotImplementedError class PasteUbuntuComValidator(GenericPastebinValidator): def validate(self): PasteUbuntuComValidator.NOT_EMPTY_FIELDS.append('format') return GenericPastebinValidator.validate(self) def getParameters(self): params = {} params['poster'] = self.conf.user params['syntax'] = self.conf.format params['content'] = self.conf.content return params class PasteDebianNetValidator(GenericPastebinValidator): def validate(self): PasteDebianNetValidator.NOT_EMPTY_FIELDS.append('format') return GenericPastebinValidator.validate(self) def getParameters(self): params = {} params['poster'] = self.conf.user params['lang'] = self.conf.format # "-1" The format, for syntax hilighting, default to plain text #params['syntax'] = self.conf.format #The format, for syntax hilighting params['code'] = self.conf.content params['remember'] = "0" #Do you want a cookie ? params['expire'] = "259200" # expire in 72h return params class GistGithubComValidator(GenericPastebinValidator): def validate(self): GistGithubComValidator.NOT_EMPTY_FIELDS.extend(['format', 'title']) return GenericPastebinValidator.validate(self) def getParameters(self): params = {} params['page'] = "/gists" params['poster'] = self.conf.user params['file_ext[gistfile1]'] = self.conf.format #The format, for syntax hilighting params['file_contents[gistfile1]'] = self.conf.content params['file_name[gistfile1]'] = self.conf.title return params class YourpasteNetValidator(GenericPastebinValidator): def validate(self): YourpasteNetValidator.NOT_EMPTY_FIELDS.extend(['format', 'title']) return GenericPastebinValidator.validate(self) def getParameters(self): params = {} params['syntax'] = self.conf.format params['name'] = self.conf.user params['desc'] = self.conf.title params['expire'] = "0" # Forever params['code'] = self.conf.content params['private'] = "0" # It's not a private post params['remember'] = "0" # Cookies? ;) params['page'] = "/paste" params['regexp'] = '">http://yourpaste.net(.*)/' return params class PasteyNetValidator(GenericPastebinValidator): def parentFixup(self, website, parentid): if parentid == "": return "" url_opener = pasteURLopener() page = url_opener.open(website + '/' + parentid, None) matches = re.split('