""" Provides a form to send an email to the blog-owner. To install: 1) Put contact.py in your plugin directory. 2) In config.py add 'contact' to py['load_plugins'] 3) Add the following variables to config.py: py['contact_urltrigger'] = "/contact" # optional, this is the default py['contact_smtp_server'] = "localhost" # required py['contact_smtp_to'] = "you@example.com" # required 4) Optionally create a template named contact. in your flavour directory. If no contact. exists a simple default is used. See _default_template below. Dependencies: - My compatibility plugin if you're not using pyblosxom 1.2+. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. Copyright (c) 2003-2007 Steven Armstrong """ __author__ = "Steven Armstrong " __version__ = "$Id:$" __url__ = "http://pyblosxom.sourceforge.net/" __description__ = "Provides a form to send an email to the blog-owner." # Python imports # Pyblosxom imports from Pyblosxom.renderers.blosxom import Renderer from Pyblosxom import tools # Variables TRIGGER = "/contact" TRIGGER_KEY = "contact_urltrigger" INIT_KEY = "contact_initiated" MESSAGE_KEY = "contact_error_message" _form_fields = ['name', 'email', 'subject', 'message'] _default_template = """

Contact me

$contact_error_message





""" def verify_installation(request): config = request.getConfiguration() retval = 1 if not 'contact_urltrigger' in config: print "Missing optional property: 'contact_urltrigger'" print "Using the default of '%s'" % TRIGGER _required = ['contact_smtp_server', 'contact_smtp_to'] for prop in _required: if not prop in config: print "Missing required property: '%s'" % prop retval = 0 return retval class ContactRenderer(Renderer): def render(self, header=1): config = self._request.getConfiguration() data = self._request.getData() http = self._request.getHttp() # path_info and root_datadir are normaly set after the cb_pathinfo callback. # but if a plugin implements cb_handle (as this one does), # cb_pathinfo is never called. # if root_datadir is not set and flavourdir is not set in config.py # an exception is thrown in BlosxomRenderer._getflavour. # so set root_datadir here explicitly to prevent that. if not 'path_info' in data: if http.get('PATH_INFO', ''): path_info = http['PATH_INFO'].split('/') path_info = [x for x in path_info if x != ''] data['path_info'] = list(path_info) if not 'root_datadir' in data: data['root_datadir'] = config['datadir'] # initialize flavour self.flavour = self._getflavour(data.get('flavour', 'html')) data['content-type'] = self.flavour['content_type'].strip() if header: self.addHeader("Status", "200 OK") if self._needs_content_type and data['content-type'] != "": self.addHeader('Content-type', '%s; charset=%s' % (data['content-type'], config.get('blog_encoding', 'iso-8859-1'))) self.showHeaders() d = {} d.update(config) d.update(data) if 'head' in self.flavour: self._outputFlavour(d, 'head') if not 'contact' in self.flavour: self.flavour['contact'] = _default_template self._outputFlavour(d, 'contact') if 'foot' in self.flavour: self._outputFlavour(d, 'foot') self.rendered = 1 def _update_config(config): if TRIGGER_KEY in config: global TRIGGER TRIGGER = config[TRIGGER_KEY] else: # set this explicitly so it's available in templates config[TRIGGER_KEY] = TRIGGER def _handle_post(request): form = request.getForm() data = request.getData() http = request.getHttp() config = request.getConfiguration() email = {} error = False error_messages = [] if not 'HTTP_REFERER' in http or \ not http['HTTP_REFERER'].startswith(config['base_url']): data[MESSAGE_KEY] = "Posting from foreign hosts not allowed.
\nUse the form below to send your message." return for field in _form_fields: if not field in form: error_messages.append("Missing required field '%s'." % field) error = True else: # strip markup parser = tools.Stripper() parser.feed(form[field].value) email[field] = parser.gettext() if not 'human_or_not' in form: error_messages.append("You didn't prove that you're human.") error = True if error: data[MESSAGE_KEY] = "
\n".join(error_messages) _remember_email(email, data) else: success, data[MESSAGE_KEY] = _send_email(email, config) if success: _forget_email(data) else: _remember_email(email, data) def _remember_email(email, data): """ Stores form fields in the data dict so they can be used to populate the form in the template. """ for key in email: data["contact_%s" % key] = email[key] def _forget_email(data): """ Resets/forgets any stored form field values. """ for key in _form_fields: key = "contact_%s" % key if key in data: del data[key] def _send_email(email, config): try: try: from email.Utils import formatdate except ImportError: from rfc822 import formatdate import smtplib smtp = smtplib.SMTP(config['contact_smtp_server']) email['to'] = config["contact_smtp_to"] email['date'] = formatdate(localtime=True) msg = """\ From: %(name)s <%(email)s> To: %(to)s Date: %(date)s Subject: %(subject)s %(message)s """ % email smtp.sendmail( from_addr=email['email'], to_addrs=config['contact_smtp_to'], msg=msg ) smtp.quit() except: if hasattr(tools, "log_exception"): tools.log_exception() return (False, "Error: Problem sending email.") else: return (True, "Thanks for feeding my mailbox ;-)") #****************************** # Callbacks #****************************** def cb_start(args): request = args['request'] http = request.getHttp() config = request.getConfiguration() _update_config(config) if http['PATH_INFO'].startswith(TRIGGER): data = request.getData() data[INIT_KEY] = True def cb_handle(args): request = args['request'] data = request.getData() if INIT_KEY in data: http = request.getHttp() if http['REQUEST_METHOD'].upper() == "POST": _handle_post(request) else: _forget_email(data) ContactRenderer(request, request.getResponse()).render() return 1 def cb_end(args): # cleanup request = args['request'] data = request.getData() if INIT_KEY in data: del data[INIT_KEY] if MESSAGE_KEY in data: del data[MESSAGE_KEY]